r23097 - gnucash/trunk/src/report - Implement Save and Save As for custom report templates

Geert Janssens gjanssens at code.gnucash.org
Sat Jul 6 16:51:23 EDT 2013


Author: gjanssens
Date: 2013-07-06 16:51:23 -0400 (Sat, 06 Jul 2013)
New Revision: 23097
Trac: http://svn.gnucash.org/trac/changeset/23097

Modified:
   gnucash/trunk/src/report/report-gnome/gnc-plugin-page-report-ui.xml
   gnucash/trunk/src/report/report-gnome/gnc-plugin-page-report.c
   gnucash/trunk/src/report/report-system/report-system.scm
   gnucash/trunk/src/report/report-system/report.scm
Log:
Implement Save and Save As for custom report templates

This fixes bug 649284 - Allow saving of Custom Reports without changing name, overwriting existing report

Modified: gnucash/trunk/src/report/report-gnome/gnc-plugin-page-report-ui.xml
===================================================================
--- gnucash/trunk/src/report/report-gnome/gnc-plugin-page-report-ui.xml	2013-07-06 20:51:11 UTC (rev 23096)
+++ gnucash/trunk/src/report/report-gnome/gnc-plugin-page-report-ui.xml	2013-07-06 20:51:23 UTC (rev 23097)
@@ -3,6 +3,7 @@
     <menu name="File" action="FileAction">
       <placeholder name="FileSavePlaceholder">
         <menuitem name="FileReportSave" action="ReportSaveAction" />
+        <menuitem name="FileReportSaveAs" action="ReportSaveAsAction" />
       </placeholder>
       <placeholder name="FilePrintPlaceholder">
         <menuitem name="FileExportPDF" action="FilePrintPDFAction"/>
@@ -36,6 +37,7 @@
       <toolitem name="ReportToolbarStop" action="ReportStopAction" />
       <separator name="ReportToolbarSep1" />
       <toolitem name="ReportToolbarSave" action="ReportSaveAction" />
+      <toolitem name="ReportToolbarSaveAs" action="ReportSaveAsAction" />
       <toolitem name="ReportToolbarExport" action="ReportExportAction" />
       <toolitem name="ReportToolbarOptions" action="ReportOptionsAction" />
       <toolitem name="ReportToolbarPrint" action="FilePrintAction" />

Modified: gnucash/trunk/src/report/report-gnome/gnc-plugin-page-report.c
===================================================================
--- gnucash/trunk/src/report/report-gnome/gnc-plugin-page-report.c	2013-07-06 20:51:11 UTC (rev 23096)
+++ gnucash/trunk/src/report/report-gnome/gnc-plugin-page-report.c	2013-07-06 20:51:23 UTC (rev 23097)
@@ -47,6 +47,7 @@
 #include <errno.h>
 
 #include "gfec.h"
+#include "dialog-custom-report.h"
 #include "gnc-component-manager.h"
 #include "gnc-engine.h"
 #include "gnc-gconf-utils.h"
@@ -173,6 +174,7 @@
 static void gnc_plugin_page_report_reload_cb(GtkAction *action, GncPluginPageReport *rep);
 static void gnc_plugin_page_report_stop_cb(GtkAction *action, GncPluginPageReport *rep);
 static void gnc_plugin_page_report_save_cb(GtkAction *action, GncPluginPageReport *rep);
+static void gnc_plugin_page_report_save_as_cb(GtkAction *action, GncPluginPageReport *rep);
 static void gnc_plugin_page_report_export_cb(GtkAction *action, GncPluginPageReport *rep);
 static void gnc_plugin_page_report_options_cb(GtkAction *action, GncPluginPageReport *rep);
 static void gnc_plugin_page_report_print_cb(GtkAction *action, GncPluginPageReport *rep);
@@ -582,8 +584,6 @@
 {
     GncPluginPageReport *report;
     GncPluginPageReportPrivate *priv;
-    GtkActionGroup *action_group;
-    GtkAction *action;
     SCM dirty_report = scm_c_eval_string("gnc:report-set-dirty?!");
     const gchar *old_name;
     gchar *new_name;
@@ -602,12 +602,7 @@
     new_name = gnc_option_db_lookup_string_option(priv->cur_odb, "General",
                "Report name", NULL);
     if (strcmp(old_name, new_name) != 0)
-    {
         main_window_update_page_name(GNC_PLUGIN_PAGE(report), new_name);
-        action_group = gnc_plugin_page_get_action_group(GNC_PLUGIN_PAGE(report));
-        action = gtk_action_group_get_action (action_group, "ReportSaveAction");
-        gtk_action_set_sensitive(action, TRUE);
-    }
     g_free(new_name);
 
     /* it's probably already dirty, but make sure */
@@ -894,8 +889,6 @@
 gnc_plugin_page_report_name_changed (GncPluginPage *page, const gchar *name)
 {
     GncPluginPageReportPrivate *priv;
-    GtkActionGroup *action_group;
-    GtkAction *action;
     static gint count = 1, max_count = 10;
     const gchar *old_name;
 
@@ -923,15 +916,6 @@
 
     /* Have to manually call the option change hook. */
     gnc_plugin_page_report_option_change_cb(page);
-
-    /* Careful. This is called at report construction time. */
-    action_group = gnc_plugin_page_get_action_group(page);
-    if (action_group)
-    {
-        /* Allow the user to save the report now. */
-        action = gtk_action_group_get_action (action_group, "ReportSaveAction");
-        gtk_action_set_sensitive(action, TRUE);
-    }
     LEAVE(" ");
 }
 
@@ -1044,14 +1028,18 @@
         G_CALLBACK (gnc_plugin_page_report_reload_cb)
     },
     {
-        "ReportSaveAction", GTK_STOCK_SAVE, N_("Add _Report"), "",
-        N_("Add the current report to the `Custom' menu for later use. "
-        "The report will be saved in the file ~/.gnucash/saved-reports-2.4. "
-        "It will be accessible as menu entry in the report menu at the "
-        "next startup of GnuCash."),
+        "ReportSaveAction", GTK_STOCK_SAVE, N_("Save _Report"), "<control><alt>s",
+        N_("Update the current report's saved configuration. "
+        "The report will be saved in the file ~/.gnucash/saved-reports-2.4. "),
         G_CALLBACK(gnc_plugin_page_report_save_cb)
     },
     {
+        "ReportSaveAsAction", GTK_STOCK_SAVE_AS, N_("Save Report As..."), "<control><alt><shift>s",
+        N_("Add the current report's configuration to the `Custom Reports' menu. "
+        "The report will be saved in the file ~/.gnucash/saved-reports-2.4. "),
+        G_CALLBACK(gnc_plugin_page_report_save_as_cb)
+    },
+    {
         "ReportExportAction", GTK_STOCK_CONVERT, N_("Export _Report"), NULL,
         N_("Export HTML-formatted report to file"),
         G_CALLBACK(gnc_plugin_page_report_export_cb)
@@ -1096,7 +1084,6 @@
 
 static const gchar *initially_insensitive_actions[] =
 {
-    "ReportSaveAction",
     NULL
 };
 
@@ -1473,28 +1460,67 @@
 }
 
 static void
-gnc_plugin_page_report_save_cb( GtkAction *action, GncPluginPageReport *report )
+gnc_plugin_page_report_save_as_cb( GtkAction *action, GncPluginPageReport *report )
 {
     GncPluginPageReportPrivate *priv;
     SCM save_func;
+    SCM rpt_id;
 
     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
     if (priv->cur_report == SCM_BOOL_F)
         return;
 
-    save_func = scm_c_eval_string("gnc:report-save-to-savefile");
-    scm_call_1(save_func, priv->cur_report);
+    /* Create a new report template based on the current report's settings
+     * and allow the user to rename the template.
+     */
+    save_func = scm_c_eval_string("gnc:report-to-template-new");
+    rpt_id = scm_call_1(save_func, priv->cur_report);
 
+    /* Open Custom Reports dialog to allow user to change the name */
+    if (!scm_is_null (rpt_id))
     {
-        GtkActionGroup *action_group =
-            gnc_plugin_page_get_action_group(GNC_PLUGIN_PAGE(report));
-        GtkAction *action =
-            gtk_action_group_get_action (action_group, "ReportSaveAction");
-        gtk_action_set_sensitive(action, FALSE);
+        GncPluginPage *reportPage = GNC_PLUGIN_PAGE (report);
+        GtkWidget *window = reportPage->window;
+
+        if (window)
+            g_return_if_fail(GNC_IS_MAIN_WINDOW(window));
+
+        gnc_ui_custom_report_edit_name (GNC_MAIN_WINDOW (window), rpt_id);
     }
+
 }
 
 static void
+gnc_plugin_page_report_save_cb( GtkAction *action, GncPluginPageReport *report )
+{
+    GncPluginPageReportPrivate *priv;
+    SCM check_func, save_func;
+    SCM rpt_id;
+
+    priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
+    if (priv->cur_report == SCM_BOOL_F)
+        return;
+
+    check_func = scm_c_eval_string("gnc:is-custom-report-type");
+    if (scm_is_true (scm_call_1 (check_func, priv->cur_report)))
+    {
+        /* The current report is already based on a custom report.
+         * Replace the existing one instead of adding a new one
+         */
+        save_func = scm_c_eval_string("gnc:report-to-template-update");
+        rpt_id = scm_call_1(save_func, priv->cur_report);
+    }
+    else
+    {
+        /* The current report is not based on a custom report.
+         * So let's create a new report template based on this report
+         * and allow the user to change the name.
+         */
+        gnc_plugin_page_report_save_as_cb (action, report);
+    }
+}
+
+static void
 gnc_plugin_page_report_export_cb( GtkAction *action, GncPluginPageReport *report )
 {
     GncPluginPageReportPrivate *priv;

Modified: gnucash/trunk/src/report/report-system/report-system.scm
===================================================================
--- gnucash/trunk/src/report/report-system/report-system.scm	2013-07-06 20:51:11 UTC (rev 23096)
+++ gnucash/trunk/src/report/report-system/report-system.scm	2013-07-06 20:51:23 UTC (rev 23097)
@@ -166,7 +166,8 @@
 (export gnc:find-report-template)
 (export gnc:report-generate-restore-forms)
 (export gnc:report-generate-saved-forms)
-(export gnc:report-save-to-savefile)
+(export gnc:report-to-template-new)
+(export gnc:report-to-template-update)
 (export gnc:report-render-html)
 (export gnc:report-run)
 (export gnc:report-templates-for-each)

Modified: gnucash/trunk/src/report/report-system/report.scm
===================================================================
--- gnucash/trunk/src/report/report-system/report.scm	2013-07-06 20:51:11 UTC (rev 23096)
+++ gnucash/trunk/src/report/report-system/report.scm	2013-07-06 20:51:23 UTC (rev 23097)
@@ -490,7 +490,22 @@
        *gnc:_report-templates_*))
     unique?))
 
+;; Generate a unique custom template name using the given string as a base
+;; If this string already exists as a custom template name, a
+;; number will be appended to it.
+(define (gnc:report-template-make-unique-name new-name)
+  (let* ((unique-name new-name)
+         (counter 0)
+         (unique? (gnc:report-template-has-unique-name? #f unique-name)))
 
+    (while (not unique?)
+      (begin
+           (set! counter (+ counter 1))
+           (set! unique-name (string-append new-name (number->string counter)))
+           (set! unique? (gnc:report-template-has-unique-name? #f unique-name))))
+    unique-name))
+
+
 ;; Load and save functions
 
 (define (gnc:report-generate-restore-forms report)
@@ -571,7 +586,7 @@
         (thunk report)))
   
   ;; save them
-  (let ((name (gnc:report-name report))
+  (let ((name (gnc:report-template-make-unique-name (gnc:report-name report)))
 	(type (gnc:report-type report))
 	(templ-name (gnc:report-template-name (hash-ref *gnc:_report-templates_* (gnc:report-type report))))
 	(options (gnc:report-options report))
@@ -604,25 +619,61 @@
                (string-append (symbol->string key) " - " (car (caddr args)))))
              #f))))
 
-(define (gnc:report-save-to-savefile report)
-  (let* ((saved-form (gnc:report-generate-saved-forms report))
-         ;; Immediate evaluate the saved form to both load it into the
-         ;; runtime, but also so we can check if it's "allowed" to actually
-         ;; be written to the saved reports file by inspecting the result.
-         ;; #Bug#342206.
+;; Convert a report into a report template and save this template in the savefile
+;; Under specific conditions the we will attempt to replace the current report's
+;; template instead of simply adding a new template to the file.
+;; These condititions are:
+;; 1. the report is an instance of an existing custom report template
+;;    (ie a template that is stored in the savefile already)
+;; 2. an overwrite is requestes by setting overwrite? to #t
+(define (gnc:report-to-template report overwrite?)
+  (let* ((custom-template-id (gnc:report-custom-template report))
+         (overwrite-ok? (and (gnc:report-template-is-custom/template-guid? custom-template-id) overwrite?))
+         ;; Generate a serialized report-template with a random guid
+         (saved-form (gnc:report-generate-saved-forms report))
+         ;; Immediatly evaluate the serialized report template to
+         ;; - check if it's error free and can be deserialized
+         ;; - load it into the runtime for immediate use by the user
+         ;; (Bug #342206)
          (save-result (eval-string saved-form)))
+
     (if (record? save-result)
-        (let ((report-port (gnc:open-saved-reports "a")))
-          (if report-port
-              (begin
-                (display saved-form report-port)
-                (close report-port)
-                ))
-          ;; Inform the calling function of the newly created template's guid
-          (gnc:report-template-report-guid save-result))
-          ;; Couldn't save report - return false
-          #f)))
+        (begin
+          ;; If it's ok to overwrite the old template, delete it now.
+          (if overwrite-ok?
+            (let ((templ-name (gnc:report-template-name (hash-ref *gnc:_report-templates_* custom-template-id))))
+              ;; We're overwriting, which needs some additional steps
+              ;; 1. Remove the newly generated template from the template list again
+              (hash-remove! *gnc:_report-templates_* (gnc:report-template-report-guid save-result))
+              ;; 2. We still have the template record available though, so adapt it to
+              ;;    the template we want to override (ie update guid and name)
+              (gnc:report-template-set-report-guid! save-result custom-template-id)
+              (gnc:report-template-set-name save-result templ-name)
+              ;; 3. Overwrite the template with the new one
+              (hash-set! *gnc:_report-templates_* custom-template-id save-result)
+              ))
 
+          ;; Regardless of how we got here, we now have a new template to write
+          ;; so let's write it
+          (if (gnc:save-all-reports)
+              (let ((templ-guid (gnc:report-template-report-guid save-result)))
+                   ;; Indicate the report was instantiated from the new template
+                   (gnc:report-set-custom-template! report templ-guid)
+                   ;; Inform the calling function of the new template's guid
+                   templ-guid)
+              #f))
+        #f)))
+
+;; Convert a report into a new report template and add this template to the save file
+(define (gnc:report-to-template-new report)
+  (gnc:report-to-template report #f))
+
+;; Get the current report's template and try to update it with the report's current
+;; settings. This will only be possible if the report was already based on a
+;; custom report template. If that's not the case, a new template will be added instead.
+(define (gnc:report-to-template-update report)
+  (gnc:report-to-template report #t))
+
 (define (gnc:report-template-save-to-savefile report-template)
   (let* ((report-port (gnc:open-saved-reports "a")))
     (if report-port



More information about the gnucash-changes mailing list