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