~ubuntu-branches/debian/stretch/gnome-builder/stretch

« back to all changes in this revision

Viewing changes to libide/ide-unsaved-files.c

  • Committer: Package Import Robot
  • Author(s): Andreas Henriksson
  • Date: 2015-10-11 12:38:45 UTC
  • Revision ID: package-import@ubuntu.com-20151011123845-a0hvkz01se0p1p5a
Tags: upstream-3.16.3
ImportĀ upstreamĀ versionĀ 3.16.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ide-unsaved-files.c
 
2
 *
 
3
 * Copyright (C) 2015 Christian Hergert <christian@hergert.me>
 
4
 *
 
5
 * This program is free software: you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation, either version 3 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
17
 */
 
18
 
 
19
#define G_LOG_DOMAIN "ide-unsaved-files"
 
20
 
 
21
#include <errno.h>
 
22
#include <glib/gstdio.h>
 
23
#include <string.h>
 
24
 
 
25
#include "ide-context.h"
 
26
#include "ide-debug.h"
 
27
#include "ide-global.h"
 
28
#include "ide-internal.h"
 
29
#include "ide-project.h"
 
30
#include "ide-unsaved-file.h"
 
31
#include "ide-unsaved-files.h"
 
32
 
 
33
typedef struct
 
34
{
 
35
  gint64           sequence;
 
36
  GFile           *file;
 
37
  GBytes          *content;
 
38
  gchar           *temp_path;
 
39
  gint             temp_fd;
 
40
  IdeUnsavedFiles *backptr;
 
41
} UnsavedFile;
 
42
 
 
43
typedef struct
 
44
{
 
45
  GPtrArray *unsaved_files;
 
46
  gint64     sequence;
 
47
} IdeUnsavedFilesPrivate;
 
48
 
 
49
typedef struct
 
50
{
 
51
  GPtrArray *unsaved_files;
 
52
  gchar     *drafts_directory;
 
53
} AsyncState;
 
54
 
 
55
G_DEFINE_TYPE_WITH_PRIVATE (IdeUnsavedFiles, ide_unsaved_files, IDE_TYPE_OBJECT)
 
56
 
 
57
gchar *
 
58
get_drafts_directory (IdeContext *context)
 
59
{
 
60
  IdeProject *project;
 
61
  const gchar *project_name;
 
62
 
 
63
  project = ide_context_get_project (context);
 
64
  project_name = ide_project_get_id (project);
 
65
 
 
66
  return g_build_filename (g_get_user_data_dir (),
 
67
                           ide_get_program_name (),
 
68
                           "drafts",
 
69
                           project_name,
 
70
                           NULL);
 
71
}
 
72
 
 
73
static void
 
74
async_state_free (gpointer data)
 
75
{
 
76
  AsyncState *state = data;
 
77
 
 
78
  if (state)
 
79
    {
 
80
      g_free (state->drafts_directory);
 
81
      g_ptr_array_unref (state->unsaved_files);
 
82
      g_slice_free (AsyncState, state);
 
83
    }
 
84
}
 
85
 
 
86
static void
 
87
unsaved_file_free (gpointer data)
 
88
{
 
89
  UnsavedFile *uf = data;
 
90
 
 
91
  if (uf)
 
92
    {
 
93
      g_clear_object (&uf->file);
 
94
      g_clear_pointer (&uf->content, g_bytes_unref);
 
95
 
 
96
      if (uf->temp_path != NULL)
 
97
        {
 
98
           g_unlink (uf->temp_path);
 
99
           g_clear_pointer (&uf->temp_path, g_free);
 
100
        }
 
101
 
 
102
      if (uf->temp_fd != -1)
 
103
        {
 
104
          g_close (uf->temp_fd, NULL);
 
105
          uf->temp_fd = -1;
 
106
        }
 
107
 
 
108
      g_slice_free (UnsavedFile, uf);
 
109
    }
 
110
}
 
111
 
 
112
static UnsavedFile *
 
113
unsaved_file_copy (const UnsavedFile *uf)
 
114
{
 
115
  UnsavedFile *copy;
 
116
 
 
117
  copy = g_slice_new0 (UnsavedFile);
 
118
  copy->file = g_object_ref (uf->file);
 
119
  copy->content = g_bytes_ref (uf->content);
 
120
 
 
121
  return copy;
 
122
}
 
123
 
 
124
static gboolean
 
125
unsaved_file_save (UnsavedFile  *uf,
 
126
                   const gchar  *path,
 
127
                   GError      **error)
 
128
{
 
129
  gboolean ret;
 
130
 
 
131
  g_assert (uf);
 
132
  g_assert (uf->content);
 
133
  g_assert (path);
 
134
 
 
135
  ret = g_file_set_contents (path,
 
136
                             g_bytes_get_data (uf->content, NULL),
 
137
                             g_bytes_get_size (uf->content),
 
138
                             error);
 
139
  return ret;
 
140
}
 
141
 
 
142
static gchar *
 
143
hash_uri (const gchar *uri)
 
144
{
 
145
  GChecksum *checksum;
 
146
  gchar *ret;
 
147
 
 
148
  checksum = g_checksum_new (G_CHECKSUM_SHA1);
 
149
  g_checksum_update (checksum, (guchar *)uri, strlen (uri));
 
150
  ret = g_strdup (g_checksum_get_string (checksum));
 
151
  g_checksum_free (checksum);
 
152
 
 
153
  return ret;
 
154
}
 
155
 
 
156
static void
 
157
ide_unsaved_files_save_worker (GTask        *task,
 
158
                               gpointer      source_object,
 
159
                               gpointer      task_data,
 
160
                               GCancellable *cancellable)
 
161
{
 
162
  GString *manifest;
 
163
  AsyncState *state = task_data;
 
164
  g_autofree gchar *manifest_path = NULL;
 
165
  GError *error = NULL;
 
166
  gsize i;
 
167
 
 
168
  g_assert (G_IS_TASK (task));
 
169
  g_assert (IDE_IS_UNSAVED_FILES (source_object));
 
170
  g_assert (state);
 
171
 
 
172
  /* ensure that the directory exists */
 
173
  if (g_mkdir_with_parents (state->drafts_directory, 0700) != 0)
 
174
    {
 
175
      error = g_error_new_literal (G_IO_ERROR,
 
176
                                   g_io_error_from_errno (errno),
 
177
                                   "Failed to create drafts directory");
 
178
      g_task_return_error (task, error);
 
179
      return;
 
180
    }
 
181
 
 
182
  manifest = g_string_new (NULL);
 
183
  manifest_path = g_build_filename (state->drafts_directory,
 
184
                                    "manifest",
 
185
                                    NULL);
 
186
 
 
187
  for (i = 0; i < state->unsaved_files->len; i++)
 
188
    {
 
189
      g_autofree gchar *path = NULL;
 
190
      g_autofree gchar *uri = NULL;
 
191
      g_autofree gchar *hash = NULL;
 
192
      UnsavedFile *uf;
 
193
 
 
194
      uf = g_ptr_array_index (state->unsaved_files, i);
 
195
 
 
196
      uri = g_file_get_uri (uf->file);
 
197
 
 
198
      g_string_append_printf (manifest, "%s\n", uri);
 
199
 
 
200
      hash = hash_uri (uri);
 
201
      path = g_build_filename (state->drafts_directory, hash, NULL);
 
202
 
 
203
      if (!unsaved_file_save (uf, path, &error))
 
204
        {
 
205
          g_task_return_error (task, error);
 
206
          goto cleanup;
 
207
        }
 
208
    }
 
209
 
 
210
  if (!g_file_set_contents (manifest_path,
 
211
                            manifest->str, manifest->len,
 
212
                            &error))
 
213
    {
 
214
      g_task_return_error (task, error);
 
215
      goto cleanup;
 
216
    }
 
217
 
 
218
  g_task_return_boolean (task, TRUE);
 
219
 
 
220
cleanup:
 
221
  g_string_free (manifest, TRUE);
 
222
}
 
223
 
 
224
static AsyncState *
 
225
async_state_new (IdeUnsavedFiles *files)
 
226
{
 
227
  IdeContext *context;
 
228
  AsyncState *state;
 
229
 
 
230
  g_assert (IDE_IS_UNSAVED_FILES (files));
 
231
 
 
232
  context = ide_object_get_context (IDE_OBJECT (files));
 
233
 
 
234
  state = g_slice_new (AsyncState);
 
235
  state->unsaved_files = g_ptr_array_new_with_free_func (unsaved_file_free);
 
236
  state->drafts_directory = get_drafts_directory (context);
 
237
 
 
238
  return state;
 
239
}
 
240
 
 
241
void
 
242
ide_unsaved_files_save_async (IdeUnsavedFiles     *files,
 
243
                              GCancellable        *cancellable,
 
244
                              GAsyncReadyCallback  callback,
 
245
                              gpointer             user_data)
 
246
{
 
247
  IdeUnsavedFilesPrivate *priv;
 
248
  g_autoptr(GTask) task = NULL;
 
249
  AsyncState *state;
 
250
  gsize i;
 
251
 
 
252
  g_return_if_fail (IDE_IS_UNSAVED_FILES (files));
 
253
  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
 
254
 
 
255
  priv = ide_unsaved_files_get_instance_private (files);
 
256
 
 
257
  state = async_state_new (files);
 
258
 
 
259
  for (i = 0; i < priv->unsaved_files->len; i++)
 
260
    {
 
261
      UnsavedFile *uf;
 
262
      UnsavedFile *uf_copy;
 
263
 
 
264
      uf = g_ptr_array_index (priv->unsaved_files, i);
 
265
      uf_copy = unsaved_file_copy (uf);
 
266
      g_ptr_array_add (state->unsaved_files, uf_copy);
 
267
    }
 
268
 
 
269
  task = g_task_new (files, cancellable, callback, user_data);
 
270
  g_task_set_task_data (task, state, async_state_free);
 
271
  g_task_run_in_thread (task, ide_unsaved_files_save_worker);
 
272
}
 
273
 
 
274
gboolean
 
275
ide_unsaved_files_save_finish (IdeUnsavedFiles  *files,
 
276
                               GAsyncResult     *result,
 
277
                               GError          **error)
 
278
{
 
279
  g_return_val_if_fail (IDE_IS_UNSAVED_FILES (files), FALSE);
 
280
  g_return_val_if_fail (G_IS_TASK (result), FALSE);
 
281
 
 
282
  return g_task_propagate_boolean (G_TASK (result), error);
 
283
}
 
284
 
 
285
static void
 
286
ide_unsaved_files_restore_worker (GTask        *task,
 
287
                                  gpointer      source_object,
 
288
                                  gpointer      task_data,
 
289
                                  GCancellable *cancellable)
 
290
{
 
291
  AsyncState *state = task_data;
 
292
  g_autofree gchar *manifest_contents = NULL;
 
293
  g_autofree gchar *manifest_path = NULL;
 
294
  gchar **lines;
 
295
  GError *error = NULL;
 
296
  gsize len;
 
297
  gsize i;
 
298
 
 
299
  IDE_ENTRY;
 
300
 
 
301
  g_assert (G_IS_TASK (task));
 
302
  g_assert (IDE_IS_UNSAVED_FILES (source_object));
 
303
  g_assert (state);
 
304
 
 
305
  manifest_path = g_build_filename (state->drafts_directory,
 
306
                                    "manifest",
 
307
                                    NULL);
 
308
 
 
309
  g_debug ("Loading drafts manifest %s", manifest_path);
 
310
 
 
311
  if (!g_file_test (manifest_path, G_FILE_TEST_IS_REGULAR))
 
312
    {
 
313
      g_task_return_boolean (task, TRUE);
 
314
      return;
 
315
    }
 
316
 
 
317
  if (!g_file_get_contents (manifest_path, &manifest_contents, &len, &error))
 
318
    {
 
319
      g_task_return_error (task, error);
 
320
      return;
 
321
    }
 
322
 
 
323
  lines = g_strsplit (manifest_contents, "\n", 0);
 
324
 
 
325
  for (i = 0; lines [i]; i++)
 
326
    {
 
327
      g_autoptr(GFile) file = NULL;
 
328
      gchar *contents = NULL;
 
329
      g_autofree gchar *hash = NULL;
 
330
      g_autofree gchar *path = NULL;
 
331
      UnsavedFile *unsaved;
 
332
      gsize data_len;
 
333
 
 
334
      if (!*lines [i])
 
335
        continue;
 
336
 
 
337
      file = g_file_new_for_uri (lines [i]);
 
338
      if (!file)
 
339
        continue;
 
340
 
 
341
      hash = hash_uri (lines [i]);
 
342
      path = g_build_filename (state->drafts_directory, hash, NULL);
 
343
 
 
344
      g_debug ("Loading draft for \"%s\" from \"%s\"", lines [i], path);
 
345
 
 
346
      if (!g_file_get_contents (path, &contents, &data_len, &error))
 
347
        {
 
348
          g_warning ("%s", error->message);
 
349
          g_clear_error (&error);
 
350
          continue;
 
351
        }
 
352
 
 
353
      unsaved = g_slice_new0 (UnsavedFile);
 
354
      unsaved->file = g_object_ref (file);
 
355
      unsaved->content = g_bytes_new_take (contents, data_len);
 
356
 
 
357
      g_ptr_array_add (state->unsaved_files, unsaved);
 
358
    }
 
359
 
 
360
  g_strfreev (lines);
 
361
 
 
362
  g_task_return_boolean (task, TRUE);
 
363
}
 
364
 
 
365
void
 
366
ide_unsaved_files_restore_async (IdeUnsavedFiles     *files,
 
367
                                 GCancellable        *cancellable,
 
368
                                 GAsyncReadyCallback  callback,
 
369
                                 gpointer             user_data)
 
370
{
 
371
  g_autoptr(GTask) task = NULL;
 
372
  AsyncState *state;
 
373
 
 
374
  g_return_if_fail (IDE_IS_UNSAVED_FILES (files));
 
375
  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
 
376
  g_return_if_fail (callback);
 
377
 
 
378
  state = async_state_new (files);
 
379
 
 
380
  task = g_task_new (files, cancellable, callback, user_data);
 
381
  g_task_set_task_data (task, state, async_state_free);
 
382
  g_task_run_in_thread (task, ide_unsaved_files_restore_worker);
 
383
}
 
384
 
 
385
gboolean
 
386
ide_unsaved_files_restore_finish (IdeUnsavedFiles  *files,
 
387
                                  GAsyncResult     *result,
 
388
                                  GError          **error)
 
389
{
 
390
  AsyncState *state;
 
391
  gsize i;
 
392
 
 
393
  g_return_val_if_fail (IDE_IS_UNSAVED_FILES (files), FALSE);
 
394
  g_return_val_if_fail (G_IS_TASK (result), FALSE);
 
395
 
 
396
  state = g_task_get_task_data (G_TASK (result));
 
397
 
 
398
  for (i = 0; i < state->unsaved_files->len; i++)
 
399
    {
 
400
      UnsavedFile *uf;
 
401
 
 
402
      uf = g_ptr_array_index (state->unsaved_files, i);
 
403
      ide_unsaved_files_update (files, uf->file, uf->content);
 
404
    }
 
405
 
 
406
  return g_task_propagate_boolean (G_TASK (result), error);
 
407
}
 
408
 
 
409
static void
 
410
ide_unsaved_files_move_to_front (IdeUnsavedFiles *self,
 
411
                                 guint            index)
 
412
{
 
413
  IdeUnsavedFilesPrivate *priv = ide_unsaved_files_get_instance_private (self);
 
414
  UnsavedFile *new_front;
 
415
  UnsavedFile *old_front;
 
416
 
 
417
  g_return_if_fail (IDE_IS_UNSAVED_FILES (self));
 
418
 
 
419
  new_front = g_ptr_array_index (priv->unsaved_files, index);
 
420
  old_front = g_ptr_array_index (priv->unsaved_files, 0);
 
421
 
 
422
  /*
 
423
   * TODO: We could shift all these items down, but it probably isnt' worth
 
424
   *       the effort. We will just move-to-front after a miss and ping
 
425
   *       pong the old item back to the front.
 
426
   */
 
427
  priv->unsaved_files->pdata[0] = new_front;
 
428
  priv->unsaved_files->pdata[index] = old_front;
 
429
}
 
430
 
 
431
static void
 
432
ide_unsaved_files_remove_draft (IdeUnsavedFiles *self,
 
433
                                GFile           *file)
 
434
{
 
435
  IdeContext *context;
 
436
  g_autofree gchar *drafts_directory = NULL;
 
437
  g_autofree gchar *uri = NULL;
 
438
  g_autofree gchar *hash = NULL;
 
439
  g_autofree gchar *path = NULL;
 
440
 
 
441
  IDE_ENTRY;
 
442
 
 
443
  g_assert (IDE_IS_UNSAVED_FILES (self));
 
444
  g_assert (G_IS_FILE (file));
 
445
 
 
446
  context = ide_object_get_context (IDE_OBJECT (self));
 
447
  drafts_directory = get_drafts_directory (context);
 
448
  uri = g_file_get_uri (file);
 
449
  hash = hash_uri (uri);
 
450
  path = g_build_filename (drafts_directory, hash, NULL);
 
451
 
 
452
  g_debug ("Removing draft for \"%s\"", uri);
 
453
 
 
454
  g_unlink (path);
 
455
 
 
456
  IDE_EXIT;
 
457
}
 
458
 
 
459
void
 
460
ide_unsaved_files_remove (IdeUnsavedFiles *self,
 
461
                          GFile           *file)
 
462
{
 
463
  IdeUnsavedFilesPrivate *priv = ide_unsaved_files_get_instance_private (self);
 
464
  guint i;
 
465
 
 
466
  g_return_if_fail (IDE_IS_UNSAVED_FILES (self));
 
467
  g_return_if_fail (G_IS_FILE (file));
 
468
 
 
469
  for (i = 0; i < priv->unsaved_files->len; i++)
 
470
    {
 
471
      UnsavedFile *unsaved;
 
472
 
 
473
      unsaved = g_ptr_array_index (priv->unsaved_files, i);
 
474
 
 
475
      if (g_file_equal (file, unsaved->file))
 
476
        {
 
477
          ide_unsaved_files_remove_draft (self, file);
 
478
          g_ptr_array_remove_index_fast (priv->unsaved_files, i);
 
479
          break;
 
480
        }
 
481
    }
 
482
}
 
483
 
 
484
static void
 
485
setup_tempfile (GFile  *file,
 
486
                gint   *temp_fd,
 
487
                gchar **temp_path)
 
488
{
 
489
  g_autofree gchar *name = NULL;
 
490
  const gchar *suffix;
 
491
  gchar *template;
 
492
 
 
493
  g_assert (G_IS_FILE (file));
 
494
  g_assert (temp_fd);
 
495
  g_assert (temp_path);
 
496
 
 
497
  *temp_fd = -1;
 
498
  *temp_path = NULL;
 
499
 
 
500
  name = g_file_get_basename (file);
 
501
  suffix = strrchr (name, '.') ?: "";
 
502
  template = g_strdup_printf ("builder_codeassistant_XXXXXX%s", suffix);
 
503
  *temp_fd = g_file_open_tmp (template, temp_path, NULL);
 
504
}
 
505
 
 
506
void
 
507
ide_unsaved_files_update (IdeUnsavedFiles *self,
 
508
                          GFile           *file,
 
509
                          GBytes          *content)
 
510
{
 
511
  IdeUnsavedFilesPrivate *priv = ide_unsaved_files_get_instance_private (self);
 
512
  UnsavedFile *unsaved;
 
513
  guint i;
 
514
 
 
515
  g_return_if_fail (IDE_IS_UNSAVED_FILES (self));
 
516
  g_return_if_fail (G_IS_FILE (file));
 
517
 
 
518
  priv->sequence++;
 
519
 
 
520
  if (!content)
 
521
    {
 
522
      ide_unsaved_files_remove (self, file);
 
523
      return;
 
524
    }
 
525
 
 
526
  for (i = 0; i < priv->unsaved_files->len; i++)
 
527
    {
 
528
      unsaved = g_ptr_array_index (priv->unsaved_files, i);
 
529
 
 
530
      if (g_file_equal (file, unsaved->file))
 
531
        {
 
532
          if (content != unsaved->content)
 
533
            {
 
534
              g_clear_pointer (&unsaved->content, g_bytes_unref);
 
535
              unsaved->content = g_bytes_ref (content);
 
536
              unsaved->sequence = priv->sequence;
 
537
            }
 
538
 
 
539
          /*
 
540
           * A file that get's updated is the most likely to get updated on
 
541
           * the next attempt. Therefore, we will simply move this entry to
 
542
           * the beginning of the array to increase it's chances of being the
 
543
           * first entry we check.
 
544
           */
 
545
          if (i != 0)
 
546
            ide_unsaved_files_move_to_front (self, i);
 
547
 
 
548
          return;
 
549
        }
 
550
    }
 
551
 
 
552
  unsaved = g_slice_new0 (UnsavedFile);
 
553
  unsaved->file = g_object_ref (file);
 
554
  unsaved->content = g_bytes_ref (content);
 
555
  unsaved->sequence = priv->sequence;
 
556
  setup_tempfile (file, &unsaved->temp_fd, &unsaved->temp_path);
 
557
 
 
558
  g_ptr_array_insert (priv->unsaved_files, 0, unsaved);
 
559
}
 
560
 
 
561
/**
 
562
 * ide_unsaved_files_to_array:
 
563
 *
 
564
 * This retrieves all of the unsaved file buffers known to the context.
 
565
 * These are handy if you need to pass modified state to parsers such as
 
566
 * clang.
 
567
 *
 
568
 * Call g_ptr_array_unref() on the resulting #GPtrArray when no longer in use.
 
569
 *
 
570
 * If you would like to hold onto an unsaved file instance, call
 
571
 * ide_unsaved_file_ref() to increment it's reference count.
 
572
 *
 
573
 * Returns: (transfer container) (element-type IdeUnsavedFile*): A #GPtrArray
 
574
 *   containing #IdeUnsavedFile elements.
 
575
 */
 
576
GPtrArray *
 
577
ide_unsaved_files_to_array (IdeUnsavedFiles *self)
 
578
{
 
579
  IdeUnsavedFilesPrivate *priv;
 
580
  GPtrArray *ar;
 
581
  gsize i;
 
582
 
 
583
  g_return_val_if_fail (IDE_IS_UNSAVED_FILES (self), NULL);
 
584
 
 
585
  priv = ide_unsaved_files_get_instance_private (self);
 
586
 
 
587
  ar = g_ptr_array_new ();
 
588
  g_ptr_array_set_free_func (ar, (GDestroyNotify)ide_unsaved_file_unref);
 
589
 
 
590
  for (i = 0; i < priv->unsaved_files->len; i++)
 
591
    {
 
592
      IdeUnsavedFile *item;
 
593
      UnsavedFile *uf;
 
594
 
 
595
      uf = g_ptr_array_index (priv->unsaved_files, i);
 
596
      item = _ide_unsaved_file_new (uf->file, uf->content, uf->temp_path, uf->sequence);
 
597
 
 
598
      g_ptr_array_add (ar, item);
 
599
    }
 
600
 
 
601
  return ar;
 
602
}
 
603
 
 
604
/**
 
605
 * ide_unsaved_files_get_unsaved_file:
 
606
 *
 
607
 * Retrieves the unsaved file content for a particular file. If no unsaved
 
608
 * file content is registered, %NULL is returned.
 
609
 *
 
610
 * Returns: (nullable) (transfer full): An #IdeUnsavedFile or %NULL.
 
611
 */
 
612
IdeUnsavedFile *
 
613
ide_unsaved_files_get_unsaved_file (IdeUnsavedFiles *self,
 
614
                                    GFile           *file)
 
615
{
 
616
  IdeUnsavedFilesPrivate *priv = ide_unsaved_files_get_instance_private (self);
 
617
  IdeUnsavedFile *ret = NULL;
 
618
  gsize i;
 
619
 
 
620
  IDE_ENTRY;
 
621
 
 
622
  g_return_val_if_fail (IDE_IS_UNSAVED_FILES (self), NULL);
 
623
 
 
624
#ifdef IDE_ENABLE_TRACE
 
625
  {
 
626
    gchar *path;
 
627
 
 
628
    path = g_file_get_path (file);
 
629
    IDE_TRACE_MSG ("%s", path);
 
630
    g_free (path);
 
631
  }
 
632
#endif
 
633
 
 
634
  for (i = 0; i < priv->unsaved_files->len; i++)
 
635
    {
 
636
      UnsavedFile *uf;
 
637
 
 
638
      uf = g_ptr_array_index (priv->unsaved_files, i);
 
639
 
 
640
      if (g_file_equal (uf->file, file))
 
641
        {
 
642
          IDE_TRACE_MSG ("Hit");
 
643
          ret = _ide_unsaved_file_new (uf->file, uf->content, uf->temp_path, uf->sequence);
 
644
          goto complete;
 
645
        }
 
646
    }
 
647
 
 
648
  IDE_TRACE_MSG ("Miss");
 
649
 
 
650
complete:
 
651
  IDE_RETURN (ret);
 
652
}
 
653
 
 
654
gint64
 
655
ide_unsaved_files_get_sequence (IdeUnsavedFiles *self)
 
656
{
 
657
  IdeUnsavedFilesPrivate *priv = ide_unsaved_files_get_instance_private (self);
 
658
 
 
659
  g_return_val_if_fail (IDE_IS_UNSAVED_FILES (self), -1);
 
660
 
 
661
  return priv->sequence;
 
662
}
 
663
 
 
664
static void
 
665
ide_unsaved_files_finalize (GObject *object)
 
666
{
 
667
  IdeUnsavedFiles *self = (IdeUnsavedFiles *)object;
 
668
  IdeUnsavedFilesPrivate *priv = ide_unsaved_files_get_instance_private (self);
 
669
 
 
670
  g_clear_pointer (&priv->unsaved_files, g_ptr_array_unref);
 
671
 
 
672
  G_OBJECT_CLASS (ide_unsaved_files_parent_class)->finalize (object);
 
673
}
 
674
 
 
675
static void
 
676
ide_unsaved_files_class_init (IdeUnsavedFilesClass *klass)
 
677
{
 
678
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
679
 
 
680
  object_class->finalize = ide_unsaved_files_finalize;
 
681
}
 
682
 
 
683
static void
 
684
ide_unsaved_files_init (IdeUnsavedFiles *self)
 
685
{
 
686
  IdeUnsavedFilesPrivate *priv = ide_unsaved_files_get_instance_private (self);
 
687
 
 
688
  priv->unsaved_files = g_ptr_array_new_with_free_func (unsaved_file_free);
 
689
}
 
690
 
 
691
void
 
692
ide_unsaved_files_clear (IdeUnsavedFiles *self)
 
693
{
 
694
  g_autoptr(GPtrArray) ar = NULL;
 
695
  gsize i;
 
696
 
 
697
  g_return_if_fail (IDE_IS_UNSAVED_FILES (self));
 
698
 
 
699
  ar = ide_unsaved_files_to_array (self);
 
700
 
 
701
  for (i = 0; i < ar->len; i++)
 
702
    {
 
703
      IdeUnsavedFile *uf;
 
704
      GFile *file;
 
705
 
 
706
      uf = g_ptr_array_index (ar, i);
 
707
      file = ide_unsaved_file_get_file (uf);
 
708
      ide_unsaved_files_remove (self, file);
 
709
    }
 
710
}