r16226 - gnucash/trunk/src - Initial autosave feature

Christian Stimming cstim at cvs.gnucash.org
Sat Jun 30 06:31:18 EDT 2007


Author: cstim
Date: 2007-06-30 06:31:14 -0400 (Sat, 30 Jun 2007)
New Revision: 16226
Trac: http://svn.gnucash.org/trac/changeset/16226

Modified:
   gnucash/trunk/src/gnome-utils/glade/preferences.glade
   gnucash/trunk/src/gnome-utils/gnc-main-window.c
   gnucash/trunk/src/gnome/schemas/apps_gnucash_general.schemas.in
Log:
Initial autosave feature


Modified: gnucash/trunk/src/gnome/schemas/apps_gnucash_general.schemas.in
===================================================================
--- gnucash/trunk/src/gnome/schemas/apps_gnucash_general.schemas.in	2007-06-28 23:12:19 UTC (rev 16225)
+++ gnucash/trunk/src/gnome/schemas/apps_gnucash_general.schemas.in	2007-06-30 10:31:14 UTC (rev 16226)
@@ -44,6 +44,30 @@
     </schema>
 
     <schema>
+      <key>/schemas/apps/gnucash/general/autosave_show_explanation</key>
+      <applyto>/apps/gnucash/general/autosave_show_explanation</applyto>
+      <owner>gnucash</owner>
+      <type>bool</type>
+      <default>TRUE</default>
+      <locale name="C">
+        <short>Show auto-save explanation</short>
+        <long>If active, GnuCash shows an explanation of the auto-save feature the first time that feature is started. Otherwise no extra explanation is shown.</long>
+      </locale>
+    </schema>
+
+    <schema>
+      <key>/schemas/apps/gnucash/general/autosave_interval_minutes</key>
+      <applyto>/apps/gnucash/general/autosave_interval_minutes</applyto>
+      <owner>gnucash</owner>
+      <type>float</type>
+      <default>3</default>
+      <locale name="C">
+        <short>Auto-save time interval</short>
+        <long>The number of minutes until saving of the data file to harddisk will be started automatically.  If zero, no saving will be started automatically.</long>
+      </locale>
+    </schema>
+
+    <schema>
       <key>/schemas/apps/gnucash/general/negative_in_red</key>
       <applyto>/apps/gnucash/general/negative_in_red</applyto>
       <owner>gnucash</owner>

Modified: gnucash/trunk/src/gnome-utils/glade/preferences.glade
===================================================================
--- gnucash/trunk/src/gnome-utils/glade/preferences.glade	2007-06-28 23:12:19 UTC (rev 16225)
+++ gnucash/trunk/src/gnome-utils/glade/preferences.glade	2007-06-30 10:31:14 UTC (rev 16226)
@@ -1640,7 +1640,7 @@
 	    <widget class="GtkTable" id="table2">
 	      <property name="border_width">6</property>
 	      <property name="visible">True</property>
-	      <property name="n_rows">16</property>
+	      <property name="n_rows">17</property>
 	      <property name="n_columns">4</property>
 	      <property name="homogeneous">False</property>
 	      <property name="row_spacing">0</property>
@@ -1776,8 +1776,8 @@
 		<packing>
 		  <property name="left_attach">1</property>
 		  <property name="right_attach">3</property>
-		  <property name="top_attach">12</property>
-		  <property name="bottom_attach">13</property>
+		  <property name="top_attach">13</property>
+		  <property name="bottom_attach">14</property>
 		  <property name="x_options">fill</property>
 		  <property name="y_options">fill</property>
 		</packing>
@@ -1805,8 +1805,8 @@
 		<packing>
 		  <property name="left_attach">0</property>
 		  <property name="right_attach">1</property>
-		  <property name="top_attach">12</property>
-		  <property name="bottom_attach">13</property>
+		  <property name="top_attach">13</property>
+		  <property name="bottom_attach">14</property>
 		  <property name="x_padding">12</property>
 		  <property name="x_options">fill</property>
 		  <property name="y_options"></property>
@@ -2071,8 +2071,8 @@
 		<packing>
 		  <property name="left_attach">0</property>
 		  <property name="right_attach">1</property>
-		  <property name="top_attach">13</property>
-		  <property name="bottom_attach">14</property>
+		  <property name="top_attach">14</property>
+		  <property name="bottom_attach">15</property>
 		  <property name="x_options">fill</property>
 		  <property name="y_options"></property>
 		</packing>
@@ -2099,8 +2099,8 @@
 		<packing>
 		  <property name="left_attach">0</property>
 		  <property name="right_attach">1</property>
-		  <property name="top_attach">14</property>
-		  <property name="bottom_attach">15</property>
+		  <property name="top_attach">15</property>
+		  <property name="bottom_attach">16</property>
 		  <property name="x_options">fill</property>
 		  <property name="y_options"></property>
 		</packing>
@@ -2128,8 +2128,8 @@
 		<packing>
 		  <property name="left_attach">0</property>
 		  <property name="right_attach">1</property>
-		  <property name="top_attach">15</property>
-		  <property name="bottom_attach">16</property>
+		  <property name="top_attach">16</property>
+		  <property name="bottom_attach">17</property>
 		  <property name="x_padding">12</property>
 		  <property name="x_options">fill</property>
 		  <property name="y_options"></property>
@@ -2152,8 +2152,8 @@
 		<packing>
 		  <property name="left_attach">1</property>
 		  <property name="right_attach">2</property>
-		  <property name="top_attach">15</property>
-		  <property name="bottom_attach">16</property>
+		  <property name="top_attach">16</property>
+		  <property name="bottom_attach">17</property>
 		  <property name="x_options">fill</property>
 		  <property name="y_options"></property>
 		</packing>
@@ -2182,6 +2182,97 @@
 		  <property name="y_options"></property>
 		</packing>
 	      </child>
+
+	      <child>
+		<widget class="GtkLabel" id="label119">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">Auto-save time _interval:</property>
+		  <property name="use_underline">True</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		  <property name="mnemonic_widget">gconf/general/autosave_interval_minutes</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
+		</widget>
+		<packing>
+		  <property name="left_attach">0</property>
+		  <property name="right_attach">1</property>
+		  <property name="top_attach">12</property>
+		  <property name="bottom_attach">13</property>
+		  <property name="x_padding">12</property>
+		  <property name="x_options">fill</property>
+		  <property name="y_options"></property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkHBox" id="hbox4">
+		  <property name="visible">True</property>
+		  <property name="homogeneous">False</property>
+		  <property name="spacing">6</property>
+
+		  <child>
+		    <widget class="GtkSpinButton" id="gconf/general/autosave_interval_minutes">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">The number of minutes until saving of the data file to harddisk will be started automatically.  If zero, no saving will be started automatically.</property>
+		      <property name="can_focus">True</property>
+		      <property name="climb_rate">1</property>
+		      <property name="digits">0</property>
+		      <property name="numeric">False</property>
+		      <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+		      <property name="snap_to_ticks">False</property>
+		      <property name="wrap">False</property>
+		      <property name="adjustment">3 0 99999 1 10 10</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">True</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="label120">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">minutes</property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="left_attach">1</property>
+		  <property name="right_attach">3</property>
+		  <property name="top_attach">12</property>
+		  <property name="bottom_attach">13</property>
+		  <property name="x_options">fill</property>
+		  <property name="y_options">fill</property>
+		</packing>
+	      </child>
 	    </widget>
 	    <packing>
 	      <property name="tab_expand">False</property>

Modified: gnucash/trunk/src/gnome-utils/gnc-main-window.c
===================================================================
--- gnucash/trunk/src/gnome-utils/gnc-main-window.c	2007-06-28 23:12:19 UTC (rev 16225)
+++ gnucash/trunk/src/gnome-utils/gnc-main-window.c	2007-06-30 10:31:14 UTC (rev 16226)
@@ -1271,12 +1271,140 @@
 		 NULL);
 }
 
+
+#define KEY_AUTOSAVE_SHOW_EXPLANATION "autosave_show_explanation"
+#define KEY_AUTOSAVE_INTERVAL "autosave_interval_minutes"
+#define AUTOSAVE_SOURCE_ID "autosave_source_id"
+/* Here's how autosave works: 
+ *
+ * Initially, the book is in state "undirty". Once the book changes
+ * state to "dirty", hence calling
+ * gnc_main_window_autosave_dirty(true), the auto-save timer is added
+ * and started. Now one out of two state changes can occur (well,
+ * three actually), depending on which event occurs first:
+ *
+ * - Either the book changes state to "undirty", hence calling
+ * gnc_main_window_autosave_dirty(false). In this case the auto-save
+ * timer is removed and all returns to the initial state with the book
+ * "undirty".
+ *
+ * - Or the auto-save timer hits its timeout, hence calling
+ * autosave_timeout_cb(). In this case gnc_file_save() is invoked, the
+ * auto-save timer is removed, and all returns to the initial state
+ * with the book "undirty".  (As an exceptional addition to this, on
+ * the very first call to autosave_timeout_cb, if the key
+ * autosave_show_explanation is true, an explanation dialog of this
+ * feature is shown to the user, and the key autosave_show_explanation
+ * is set to false to not show this dialog again.)
+ *
+ * - As a third possibility, the book can also change state to
+ * "closing", in which case the autosave_remove_timer_cb is called
+ * that removes the auto-save timer and all returns to the initial
+ * state with the book "undirty".
+ */
+static gboolean autosave_timeout_cb(gpointer user_data)
+{
+  /* QofBook *book = user_data; */
+  gboolean show_explanation;
+
+  /* Is there already a save in progress? If yes, return FALSE so that
+     the timeout is automatically destroyed and the function will not
+     be called again. */
+  if (gnc_file_save_in_progress() || !gnc_current_session_exist())
+    return FALSE;
+
+  /* Lookup gconf key to show an explanatory dialog the very first
+     time this becomes active. */
+  show_explanation =
+    gnc_gconf_get_bool(GCONF_GENERAL, KEY_AUTOSAVE_SHOW_EXPLANATION, NULL);
+  if (show_explanation) {
+    guint interval_mins =
+      gnc_gconf_get_float(GCONF_GENERAL, KEY_AUTOSAVE_INTERVAL, NULL);
+    /* The autosave timeout has occurred for the very first
+       time. Explain this feature. */
+    gnc_info_dialog(NULL,
+		      _("Your data file needs to be saved to your harddisk to save your changes.  GnuCash has a feature to save the file automatically every %d minutes.  This feature is being activated the very first time right now. \n\n"
+			"If you like to change the time interval, you can do so under Edit -> Preferences -> General -> Auto-save time interval.  If you like to switch off this feature, set the time interval to zero and no auto-save will occur anymore.\n\n"
+			"Press \"Close\" now so that your file will be saved."),
+		      interval_mins);
+    /* Don't show this explanation again. */
+    gnc_gconf_set_bool(GCONF_GENERAL, KEY_AUTOSAVE_SHOW_EXPLANATION, FALSE, NULL);
+  }
+
+  /* Timeout has passed - save the file. */
+  gnc_file_save();
+
+  /* Return FALSE so that the timeout is automatically destroyed and
+     the function will not be called again. */
+  return FALSE;
+}
+static void 
+autosave_remove_timer_cb(QofBook *book, gpointer key, gpointer user_data)
+{
+  guint autosave_source_id = GPOINTER_TO_UINT(user_data);
+  /* Remove the timer that would have triggered the next autosave */
+  if (autosave_source_id > 0)
+    g_source_remove (autosave_source_id);
+}
+static void autosave_remove_timer(QofBook *book)
+{
+  autosave_remove_timer_cb(book, AUTOSAVE_SOURCE_ID,
+			   qof_book_get_data(book, AUTOSAVE_SOURCE_ID));
+}
+static void autosave_add_timer(QofBook *book)
+{
+  guint interval_mins =
+    gnc_gconf_get_float(GCONF_GENERAL, KEY_AUTOSAVE_INTERVAL, NULL);
+
+  /* Interval zero means auto-save is turned off. */
+  if (interval_mins > 0) {
+    /* Add a new timer (timeout) that runs until the next autosave
+       timeout. */
+    guint autosave_source_id =
+#if GLIB_CHECK_VERSION(2, 14, 0)
+      /* g_timeout_add_seconds is much more suitable here, but is new in
+	 glib-2.14. */
+      g_timeout_add_seconds(interval_mins * 60,
+			    autosave_timeout_cb, book);
+#else
+    g_timeout_add(interval_mins * 60 * 1000,
+		  autosave_timeout_cb, book);
+#endif
+    g_debug("Added new auto save timer with id %d\n", autosave_source_id);
+
+    /* Save the event source id for a potential removal, and also
+       set the callback upon book closing */
+    qof_book_set_data_fin(book, AUTOSAVE_SOURCE_ID,
+			  GUINT_TO_POINTER(autosave_source_id),
+			  autosave_remove_timer_cb);
+  }
+}
+static void gnc_main_window_autosave_dirty (QofBook *book, gboolean dirty)
+{
+  if (dirty) {
+    /* Book state changed from non-dirty to dirty. Start the autosave
+       timer. */
+    /* First stop a potentially running old timer. */
+    autosave_remove_timer(book);
+    /* Add a new timer (timeout) that runs until the next autosave
+       timeout. */
+    autosave_add_timer(book);
+  } else {
+    /* Book state changed from dirty to non-dirty (probably due to
+       saving). Delete the running autosave timer. */
+    autosave_remove_timer(book);
+  }
+}
+
 static void
 gnc_main_window_book_dirty_cb (QofBook *book,
 			       gboolean dirty,
 			       gpointer user_data)
 {
   gnc_main_window_update_all_titles();
+
+  /* Auto-save feature */
+  gnc_main_window_autosave_dirty(book, dirty);
 }
 
 static void



More information about the gnucash-changes mailing list