diff --git a/src/gnome-utils/glade/preferences.glade b/src/gnome-utils/glade/preferences.glade
index aeeb1a1238..872e011626 100644
--- a/src/gnome-utils/glade/preferences.glade
+++ b/src/gnome-utils/glade/preferences.glade
@@ -1640,7 +1640,7 @@
6
True
- 16
+ 17
4
False
0
@@ -1776,8 +1776,8 @@
1
3
- 12
- 13
+ 13
+ 14
fill
fill
@@ -1805,8 +1805,8 @@
0
1
- 12
- 13
+ 13
+ 14
12
fill
@@ -2071,8 +2071,8 @@
0
1
- 13
- 14
+ 14
+ 15
fill
@@ -2099,8 +2099,8 @@
0
1
- 14
- 15
+ 15
+ 16
fill
@@ -2128,8 +2128,8 @@
0
1
- 15
- 16
+ 16
+ 17
12
fill
@@ -2152,8 +2152,8 @@
1
2
- 15
- 16
+ 16
+ 17
fill
@@ -2182,6 +2182,97 @@
+
+
+
+ True
+ Auto-save time _interval:
+ True
+ False
+ GTK_JUSTIFY_LEFT
+ False
+ False
+ 0
+ 0.5
+ 0
+ 0
+ gconf/general/autosave_interval_minutes
+ PANGO_ELLIPSIZE_NONE
+ -1
+ False
+ 0
+
+
+ 0
+ 1
+ 12
+ 13
+ 12
+ fill
+
+
+
+
+
+
+ True
+ False
+ 6
+
+
+
+ True
+ The number of minutes until saving of the data file to harddisk will be started automatically. If zero, no saving will be started automatically.
+ True
+ 1
+ 0
+ False
+ GTK_UPDATE_ALWAYS
+ False
+ False
+ 3 0 99999 1 10 10
+
+
+ 0
+ False
+ True
+
+
+
+
+
+ True
+ minutes
+ False
+ False
+ GTK_JUSTIFY_LEFT
+ False
+ False
+ 0
+ 0.5
+ 0
+ 0
+ PANGO_ELLIPSIZE_NONE
+ -1
+ False
+ 0
+
+
+ 0
+ False
+ False
+
+
+
+
+ 1
+ 3
+ 12
+ 13
+ fill
+ fill
+
+
False
diff --git a/src/gnome-utils/gnc-main-window.c b/src/gnome-utils/gnc-main-window.c
index c37b797900..a6844ba195 100644
--- a/src/gnome-utils/gnc-main-window.c
+++ b/src/gnome-utils/gnc-main-window.c
@@ -1271,12 +1271,140 @@ gnc_main_window_update_all_titles (void)
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
diff --git a/src/gnome/schemas/apps_gnucash_general.schemas.in b/src/gnome/schemas/apps_gnucash_general.schemas.in
index 0dee8870c9..a38b7c05c1 100644
--- a/src/gnome/schemas/apps_gnucash_general.schemas.in
+++ b/src/gnome/schemas/apps_gnucash_general.schemas.in
@@ -43,6 +43,30 @@
+
+ /schemas/apps/gnucash/general/autosave_show_explanation
+ /apps/gnucash/general/autosave_show_explanation
+ gnucash
+ bool
+ TRUE
+
+ Show auto-save explanation
+ If active, GnuCash shows an explanation of the auto-save feature the first time that feature is started. Otherwise no extra explanation is shown.
+
+
+
+
+ /schemas/apps/gnucash/general/autosave_interval_minutes
+ /apps/gnucash/general/autosave_interval_minutes
+ gnucash
+ float
+ 3
+
+ Auto-save time interval
+ The number of minutes until saving of the data file to harddisk will be started automatically. If zero, no saving will be started automatically.
+
+
+
/schemas/apps/gnucash/general/negative_in_red
/apps/gnucash/general/negative_in_red