[gtksourceview/wip/loader-saver: 16/23] File saving: check if the file is externally modified



commit e890e64688f37936cf1ac33ab261309dbe074ea6
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Mon Jun 9 21:33:24 2014 +0200

    File saving: check if the file is externally modified
    
    Store the modification time in GtkSourceFile, and update the value on
    each file loading and saving.

 gtksourceview/gtksourcefile.c       |   44 +++++++++++++++
 gtksourceview/gtksourcefile.h       |    8 +++
 gtksourceview/gtksourcefileloader.c |    7 +++
 gtksourceview/gtksourcefilesaver.c  |  102 +++++++++++++++++++++++++++++++++-
 gtksourceview/gtksourcefilesaver.h  |    5 ++-
 5 files changed, 162 insertions(+), 4 deletions(-)
---
diff --git a/gtksourceview/gtksourcefile.c b/gtksourceview/gtksourcefile.c
index b5fcbe8..ae3929b 100644
--- a/gtksourceview/gtksourcefile.c
+++ b/gtksourceview/gtksourcefile.c
@@ -65,6 +65,13 @@ struct _GtkSourceFilePrivate
 
        GtkSourceMountOperationFactory mount_operation_factory;
        gpointer mount_operation_userdata;
+
+       /* Last known modification time of 'location'. The value is updated on a
+        * file loading or file saving.
+        */
+       GTimeVal modification_time;
+
+       guint modification_time_set : 1;
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE (GtkSourceFile, gtk_source_file, G_TYPE_OBJECT)
@@ -300,6 +307,9 @@ _gtk_source_file_set_location (GtkSourceFile *file,
                g_clear_object (&file->priv->location);
                file->priv->location = g_object_ref (location);
                g_object_notify (G_OBJECT (file), "location");
+
+               /* The modification_time is for the old location. */
+               file->priv->modification_time_set = FALSE;
        }
 }
 
@@ -441,3 +451,37 @@ _gtk_source_file_create_mount_operation (GtkSourceFile *file)
                file->priv->mount_operation_factory (file->priv->mount_operation_userdata) :
                g_mount_operation_new ();
 }
+
+gboolean
+_gtk_source_file_get_modification_time (GtkSourceFile *file,
+                                       GTimeVal      *modification_time)
+{
+       g_assert (modification_time != NULL);
+
+       if (file == NULL)
+       {
+               return FALSE;
+       }
+
+       g_return_val_if_fail (GTK_SOURCE_IS_FILE (file), FALSE);
+
+       if (file->priv->modification_time_set)
+       {
+               *modification_time = file->priv->modification_time;
+       }
+
+       return file->priv->modification_time_set;
+}
+
+void
+_gtk_source_file_set_modification_time (GtkSourceFile *file,
+                                       GTimeVal       modification_time)
+{
+       if (file != NULL)
+       {
+               g_return_if_fail (GTK_SOURCE_IS_FILE (file));
+
+               file->priv->modification_time = modification_time;
+               file->priv->modification_time_set = TRUE;
+       }
+}
diff --git a/gtksourceview/gtksourcefile.h b/gtksourceview/gtksourcefile.h
index be41162..912cf47 100644
--- a/gtksourceview/gtksourcefile.h
+++ b/gtksourceview/gtksourcefile.h
@@ -89,6 +89,14 @@ void          _gtk_source_file_set_compression_type          (GtkSourceFile            
*file,
 G_GNUC_INTERNAL
 GMountOperation        *_gtk_source_file_create_mount_operation        (GtkSourceFile *file);
 
+G_GNUC_INTERNAL
+gboolean        _gtk_source_file_get_modification_time         (GtkSourceFile *file,
+                                                                GTimeVal      *modification_time);
+
+G_GNUC_INTERNAL
+void            _gtk_source_file_set_modification_time         (GtkSourceFile *file,
+                                                                GTimeVal       modification_time);
+
 G_END_DECLS
 
 #endif /* __GTK_SOURCE_FILE_H__ */
diff --git a/gtksourceview/gtksourcefileloader.c b/gtksourceview/gtksourcefileloader.c
index 98ae94e..4a41e99 100644
--- a/gtksourceview/gtksourcefileloader.c
+++ b/gtksourceview/gtksourcefileloader.c
@@ -956,6 +956,13 @@ gtk_source_file_loader_load_finish (GtkSourceFileLoader  *loader,
 
                _gtk_source_file_set_compression_type (loader->priv->file,
                                                       loader->priv->auto_detected_compression_type);
+
+               if (g_file_info_has_attribute (loader->priv->info, G_FILE_ATTRIBUTE_TIME_MODIFIED))
+               {
+                       GTimeVal modification_time;
+                       g_file_info_get_modification_time (loader->priv->info, &modification_time);
+                       _gtk_source_file_set_modification_time (loader->priv->file, modification_time);
+               }
        }
 
        reset (loader);
diff --git a/gtksourceview/gtksourcefilesaver.c b/gtksourceview/gtksourcefilesaver.c
index 4f814c0..ae62da8 100644
--- a/gtksourceview/gtksourcefilesaver.c
+++ b/gtksourceview/gtksourcefilesaver.c
@@ -484,7 +484,6 @@ query_info_cb (GFile              *file,
               g_print ("Finished query info on file\n");
        });
 
-       /* TODO update mtime stored in GtkSourceFile */
        g_clear_object (&saver->priv->info);
        saver->priv->info = g_file_query_info_finish (file, result, &error);
 
@@ -793,6 +792,96 @@ begin_write (GtkSourceFileSaver *saver)
 }
 
 static void
+check_externally_modified_cb (GFile              *location,
+                             GAsyncResult       *result,
+                             GtkSourceFileSaver *saver)
+{
+       GFileInfo *info;
+       GTimeVal old_mtime;
+       GTimeVal cur_mtime;
+       GError *error = NULL;
+
+       DEBUG ({
+              g_print ("%s\n", G_STRFUNC);
+       });
+
+       info = g_file_query_info_finish (location, result, &error);
+
+       if (error != NULL)
+       {
+               if (error->domain == G_IO_ERROR &&
+                   error->code == G_IO_ERROR_NOT_MOUNTED &&
+                   !saver->priv->tried_mount)
+               {
+                       recover_not_mounted (saver);
+                       g_error_free (error);
+                       return;
+               }
+
+               /* It's perfectly fine if the file doesn't exist yet. */
+               if (error->domain != G_IO_ERROR ||
+                   error->code != G_IO_ERROR_NOT_FOUND)
+               {
+                       DEBUG ({
+                              g_print ("Check externally modified failed: %s\n", error->message);
+                       });
+
+                       g_task_return_error (saver->priv->task, error);
+                       return;
+               }
+               else
+               {
+                       g_error_free (error);
+               }
+       }
+
+       if (_gtk_source_file_get_modification_time (saver->priv->file, &old_mtime) &&
+           info != NULL &&
+           g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED))
+       {
+               g_file_info_get_modification_time (info, &cur_mtime);
+
+               if (old_mtime.tv_sec != cur_mtime.tv_sec ||
+                   old_mtime.tv_usec != cur_mtime.tv_usec)
+               {
+                       DEBUG ({
+                              g_print ("The file is externally modified\n");
+                       });
+
+                       g_task_return_new_error (saver->priv->task,
+                                                GTK_SOURCE_FILE_SAVER_ERROR,
+                                                GTK_SOURCE_FILE_SAVER_ERROR_EXTERNALLY_MODIFIED,
+                                                "The file is externally modified");
+                       g_object_unref (info);
+                       return;
+               }
+       }
+
+       begin_write (saver);
+
+       if (info != NULL)
+       {
+               g_object_unref (info);
+       }
+}
+
+static void
+check_externally_modified (GtkSourceFileSaver *saver)
+{
+       DEBUG ({
+              g_print ("%s\n", G_STRFUNC);
+       });
+
+       g_file_query_info_async (saver->priv->location,
+                                G_FILE_ATTRIBUTE_TIME_MODIFIED,
+                                G_FILE_QUERY_INFO_NONE,
+                                g_task_get_priority (saver->priv->task),
+                                g_task_get_cancellable (saver->priv->task),
+                                (GAsyncReadyCallback) check_externally_modified_cb,
+                                saver);
+}
+
+static void
 mount_cb (GFile              *file,
          GAsyncResult       *result,
          GtkSourceFileSaver *saver)
@@ -810,7 +899,7 @@ mount_cb (GFile              *file,
                g_task_return_error (saver->priv->task, error);
        }
 
-       begin_write (saver);
+       check_externally_modified (saver);
 }
 
 static void
@@ -1176,7 +1265,7 @@ gtk_source_file_saver_save_async (GtkSourceFileSaver     *saver,
                                                                         saver->priv->newline_type,
                                                                         implicit_trailing_newline);
 
-       begin_write (saver);
+       check_externally_modified (saver);
 }
 
 /**
@@ -1220,6 +1309,13 @@ gtk_source_file_saver_save_finish (GtkSourceFileSaver  *saver,
 
                _gtk_source_file_set_compression_type (saver->priv->file,
                                                       saver->priv->compression_type);
+
+               if (g_file_info_has_attribute (saver->priv->info, G_FILE_ATTRIBUTE_TIME_MODIFIED))
+               {
+                       GTimeVal modification_time;
+                       g_file_info_get_modification_time (saver->priv->info, &modification_time);
+                       _gtk_source_file_set_modification_time (saver->priv->file, modification_time);
+               }
        }
 
        reset (saver);
diff --git a/gtksourceview/gtksourcefilesaver.h b/gtksourceview/gtksourcefilesaver.h
index 0a65ff5..c5afb78 100644
--- a/gtksourceview/gtksourcefilesaver.h
+++ b/gtksourceview/gtksourcefilesaver.h
@@ -47,12 +47,15 @@ typedef struct _GtkSourceFileSaverPrivate GtkSourceFileSaverPrivate;
  * GtkSourceFileSaverError:
  * @GTK_SOURCE_FILE_SAVER_ERROR_INVALID_CHARS: The buffer contains invalid
  *   characters.
+ * @GTK_SOURCE_FILE_SAVER_ERROR_EXTERNALLY_MODIFIED: The file is externally
+ *   modified.
  *
  * An error code used with the %GTK_SOURCE_FILE_SAVER_ERROR domain.
  */
 typedef enum
 {
-       GTK_SOURCE_FILE_SAVER_ERROR_INVALID_CHARS
+       GTK_SOURCE_FILE_SAVER_ERROR_INVALID_CHARS,
+       GTK_SOURCE_FILE_SAVER_ERROR_EXTERNALLY_MODIFIED
 } GtkSourceFileSaverError;
 
 struct _GtkSourceFileSaver


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]