GnuCash 2.4.99
gnc-plugin-page-report.c
Go to the documentation of this file.
00001 /* gnc-plugin-page-report.c
00002  * Copyright (C) 2004 Joshua Sled <jsled@asynchronous.org>
00003  * Copyright (C) 2005 David Hampton <hampton@employees.org>
00004  *
00005  * Originally from window-report.c:
00006  * Copyright (C) 1997 Robin D. Clark
00007  * Copyright (C) 1998 Linas Vepstas
00008  * Copyright (C) 1999 Jeremy Collins ( gtk-xmhtml port )
00009  * Copyright (C) 2000 Dave Peticolas
00010  * Copyright (C) 2000 Bill Gribble
00011  *
00012  * This program is free software; you can redistribute it and/or
00013  * modify it under the terms of the GNU General Public License as
00014  * published by the Free Software Foundation; either version 2 of
00015  * the License, or (at your option) any later version.
00016  *
00017  * This program is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  * GNU General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU General Public License
00023  * along with this program; if not, contact:
00024  *
00025  * Free Software Foundation           Voice:  +1-617-542-5942
00026  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
00027  * Boston, MA  02110-1301,  USA       gnu@gnu.org
00028  */
00029 
00040 #include "config.h"
00041 
00042 #include <gtk/gtk.h>
00043 #include <glib/gi18n.h>
00044 #include <glib/gstdio.h>
00045 #include <libguile.h>
00046 #include <sys/stat.h>
00047 #include <errno.h>
00048 
00049 #include "gfec.h"
00050 #include "gnc-component-manager.h"
00051 #include "gnc-engine.h"
00052 #include "gnc-gconf-utils.h"
00053 #include "gnc-gnome-utils.h"
00054 #include "gnc-html-history.h"
00055 #include "gnc-html.h"
00056 #include "gnc-html-factory.h"
00057 #include "gnc-file.h"
00058 #include "gnc-plugin.h"
00059 #include "gnc-plugin-page-report.h"
00060 #include "gnc-plugin-file-history.h"
00061 #include "gnc-report.h"
00062 #include "gnc-session.h"
00063 #include "gnc-ui-util.h"
00064 #include "gnc-ui.h"
00065 #include "gnc-window.h"
00066 #include "guile-util.h"
00067 #include "option-util.h"
00068 #include "window-report.h"
00069 #include "swig-runtime.h"
00070 #include "app-utils/business-options.h"
00071 #include "gnome-utils/gnc-icons.h"
00072 #include "gnome-utils/print-session.h"
00073 
00074 #define WINDOW_REPORT_CM_CLASS "window-report"
00075 
00076 /* NW: you can add GNC_MOD_REPORT to gnc-engine.h
00077 or simply define it locally. Any unique string with
00078 a gnucash- prefix will do. Then just set a log level
00079 with qof_log_set_level().*/
00080 static QofLogModule log_module = GNC_MOD_GUI;
00081 
00082 static GObjectClass *parent_class = NULL;
00083 
00084 // A static GHashTable to record the usage count for each printer
00085 // output name. FIXME: Currently this isn't cleaned up at program
00086 // shutdown because there isn't a place to easily insert a finalize()
00087 // function for this. Oh well.
00088 static GHashTable *static_report_printnames = NULL;
00089 
00090 // Property-id values.
00091 enum
00092 {
00093     PROP_0,
00094     PROP_REPORT_ID,
00095 };
00096 
00097 typedef struct GncPluginPageReportPrivate
00098 {
00100     int reportId;
00101     gint component_manager_id;
00102 
00104     SCM cur_report;
00106     GNCOptionDB *cur_odb;
00107     SCM option_change_cb_id;
00108 
00109     /* initial_report is special; it's the one that's saved and
00110      * restored.  The name_change_callback only gets called when
00111      * the initial_report name is changed. */
00112     SCM          initial_report;
00113     GNCOptionDB  * initial_odb;
00114     SCM          name_change_cb_id;
00115 
00116     /* keep a list of edited reports so that we can destroy them when
00117      * the window is closed. */
00118     SCM          edited_reports;
00119 
00120     /* This is set to mark the fact that we need to reload the html */
00121     gboolean    need_reload;
00122 
00123     /* The page is in the process of reloading the html */
00124     gboolean    reloading;
00125 
00127 //        gnc_html *html;
00128     GncHtml *html;
00129 
00131     GtkContainer *container;
00132 } GncPluginPageReportPrivate;
00133 
00134 #define GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(o)  \
00135    (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_PLUGIN_PAGE_REPORT, GncPluginPageReportPrivate))
00136 
00137 static void gnc_plugin_page_report_class_init( GncPluginPageReportClass *klass );
00138 static void gnc_plugin_page_report_init( GncPluginPageReport *plugin_page );
00139 static GObject *gnc_plugin_page_report_constructor(GType this_type, guint n_properties, GObjectConstructParam *properties);
00140 static void gnc_plugin_page_report_finalize (GObject *object);
00141 static void gnc_plugin_page_report_setup( GncPluginPage *ppage );
00142 
00143 static void gnc_plugin_page_report_constr_init(GncPluginPageReport *plugin_page, gint reportId);
00144 
00145 static GtkWidget* gnc_plugin_page_report_create_widget( GncPluginPage *plugin_page );
00146 static void gnc_plugin_page_report_destroy_widget( GncPluginPage *plugin_page );
00147 static void gnc_plugin_page_report_save_page (GncPluginPage *plugin_page, GKeyFile *file, const gchar *group);
00148 static GncPluginPage *gnc_plugin_page_report_recreate_page (GtkWidget *window, GKeyFile *file, const gchar *group);
00149 static void gnc_plugin_page_report_name_changed (GncPluginPage *page, const gchar *name);
00150 static void gnc_plugin_page_report_update_edit_menu (GncPluginPage *page, gboolean hide);
00151 static gboolean gnc_plugin_page_report_finish_pending (GncPluginPage *page);
00152 
00153 static int gnc_plugin_page_report_check_urltype(URLType t);
00154 //static void gnc_plugin_page_report_load_cb(gnc_html * html, URLType type,
00155 static void gnc_plugin_page_report_load_cb(GncHtml * html, URLType type,
00156         const gchar * location, const gchar * label,
00157         gpointer data);
00158 static void gnc_plugin_page_report_expose_event_cb(GtkWidget *unused, GdkEventExpose *unused1, gpointer data);
00159 static void gnc_plugin_page_report_refresh (gpointer data);
00160 static void gnc_plugin_page_report_set_fwd_button(GncPluginPageReport * page, int enabled);
00161 static void gnc_plugin_page_report_set_back_button(GncPluginPageReport * page, int enabled);
00162 static void gnc_plugin_page_report_history_destroy_cb(gnc_html_history_node * node, gpointer user_data);
00163 static void close_handler(gpointer user_data);
00164 void gnc_plugin_page_report_destroy(GncPluginPageReportPrivate *priv);
00165 static void gnc_plugin_page_report_option_change_cb(gpointer data);
00166 
00167 void gnc_plugin_page_report_remove_edited_report(GncPluginPageReportPrivate *priv, SCM report);
00168 void gnc_plugin_page_report_add_edited_report(GncPluginPageReportPrivate *priv, SCM report);
00169 void gnc_plugin_page_report_raise_editor(SCM report);
00170 
00171 static void gnc_plugin_page_report_forw_cb(GtkAction *action, GncPluginPageReport *rep);
00172 static void gnc_plugin_page_report_back_cb(GtkAction *action, GncPluginPageReport *rep);
00173 static void gnc_plugin_page_report_reload_cb(GtkAction *action, GncPluginPageReport *rep);
00174 static void gnc_plugin_page_report_stop_cb(GtkAction *action, GncPluginPageReport *rep);
00175 static void gnc_plugin_page_report_save_cb(GtkAction *action, GncPluginPageReport *rep);
00176 static void gnc_plugin_page_report_export_cb(GtkAction *action, GncPluginPageReport *rep);
00177 static void gnc_plugin_page_report_options_cb(GtkAction *action, GncPluginPageReport *rep);
00178 static void gnc_plugin_page_report_print_cb(GtkAction *action, GncPluginPageReport *rep);
00179 static void gnc_plugin_page_report_exportpdf_cb(GtkAction *action, GncPluginPageReport *rep);
00180 static void gnc_plugin_page_report_copy_cb(GtkAction *action, GncPluginPageReport *rep);
00181 
00182 GType
00183 gnc_plugin_page_report_get_type (void)
00184 {
00185     static GType gnc_plugin_page_report_type = 0;
00186 
00187     if (gnc_plugin_page_report_type == 0)
00188     {
00189         static const GTypeInfo our_info =
00190         {
00191             sizeof (GncPluginPageReportClass),
00192             NULL,
00193             NULL,
00194             (GClassInitFunc) gnc_plugin_page_report_class_init,
00195             NULL,
00196             NULL,
00197             sizeof (GncPluginPageReport),
00198             0,
00199             (GInstanceInitFunc) gnc_plugin_page_report_init
00200         };
00201 
00202         gnc_plugin_page_report_type = g_type_register_static (GNC_TYPE_PLUGIN_PAGE,
00203                                       "GncPluginPageReport",
00204                                       &our_info, 0);
00205     }
00206 
00207     return gnc_plugin_page_report_type;
00208 }
00209 
00210 static void
00211 gnc_plugin_page_report_get_property( GObject *obj,
00212                                      guint prop_id,
00213                                      GValue *value,
00214                                      GParamSpec *pspec )
00215 {
00216     GncPluginPageReport *rep;
00217     GncPluginPageReportPrivate *priv;
00218 
00219     rep = GNC_PLUGIN_PAGE_REPORT( obj );
00220     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(rep);
00221 
00222     switch ( prop_id )
00223     {
00224     case PROP_REPORT_ID:
00225         g_value_set_int( value, priv->reportId );
00226         break;
00227     default:
00228         PERR( "Unknown property id %d", prop_id );
00229         break;
00230     }
00231 }
00232 
00233 static void
00234 gnc_plugin_page_report_set_property( GObject *obj,
00235                                      guint prop_id,
00236                                      const GValue *value,
00237                                      GParamSpec *pspec )
00238 {
00239     GncPluginPageReport *rep;
00240     GncPluginPageReportPrivate *priv;
00241 
00242     rep = GNC_PLUGIN_PAGE_REPORT( obj );
00243     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(rep);
00244 
00245     DEBUG( "setting property with id %d / %p to value %d",
00246            prop_id, priv, g_value_get_int( value ) );
00247 
00248     switch ( prop_id )
00249     {
00250     case PROP_REPORT_ID:
00251         priv->reportId = g_value_get_int( value );
00252         break;
00253     default:
00254         PERR( "unknown property id %d", prop_id );
00255         break;
00256     }
00257 
00258 }
00259 
00260 static void
00261 gnc_plugin_page_report_class_init (GncPluginPageReportClass *klass)
00262 {
00263     GObjectClass *object_class = G_OBJECT_CLASS (klass);
00264     GncPluginPageClass *gnc_plugin_page_class = GNC_PLUGIN_PAGE_CLASS(klass);
00265 
00266     parent_class = g_type_class_peek_parent (klass);
00267 
00268     object_class->constructor = gnc_plugin_page_report_constructor;
00269     object_class->finalize = gnc_plugin_page_report_finalize;
00270 
00271     object_class->set_property = gnc_plugin_page_report_set_property;
00272     object_class->get_property = gnc_plugin_page_report_get_property;
00273 
00274     // FIXME: stock reporting icon?
00275     //gnc_plugin_page_class->tab_icon        = GNC_STOCK_ACCOUNT;
00276     gnc_plugin_page_class->plugin_name     = GNC_PLUGIN_PAGE_REPORT_NAME;
00277 
00278     gnc_plugin_page_class->create_widget   = gnc_plugin_page_report_create_widget;
00279     gnc_plugin_page_class->destroy_widget  = gnc_plugin_page_report_destroy_widget;
00280     gnc_plugin_page_class->save_page       = gnc_plugin_page_report_save_page;
00281     gnc_plugin_page_class->recreate_page   = gnc_plugin_page_report_recreate_page;
00282     gnc_plugin_page_class->page_name_changed = gnc_plugin_page_report_name_changed;
00283     gnc_plugin_page_class->update_edit_menu_actions = gnc_plugin_page_report_update_edit_menu;
00284     gnc_plugin_page_class->finish_pending   = gnc_plugin_page_report_finish_pending;
00285 
00286     g_type_class_add_private(klass, sizeof(GncPluginPageReportPrivate));
00287 
00288     // create the "reportId" property
00289     g_object_class_install_property( object_class,
00290                                      PROP_REPORT_ID,
00291                                      g_param_spec_int( "report-id",
00292                                              _("The numeric ID of the report."),
00293                                              _("The numeric ID of the report."),
00294                                              -1, G_MAXINT, -1, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE ) );
00295 
00296     /* JSLED: report-selected?
00297         plugin_page_signals[ACCOUNT_SELECTED] =
00298           g_signal_new ("account_selected",
00299                         G_OBJECT_CLASS_TYPE (object_class),
00300                         G_SIGNAL_RUN_FIRST,
00301                         G_STRUCT_OFFSET (GncPluginPageReportClass, account_selected),
00302                         NULL, NULL,
00303                         g_cclosure_marshal_VOID__POINTER,
00304                         G_TYPE_NONE, 1,
00305                         G_TYPE_POINTER);
00306     */
00307 
00308     // Also initialize the report name usage count table
00309     if (!static_report_printnames)
00310         static_report_printnames = g_hash_table_new_full(g_str_hash,
00311                                    g_str_equal, g_free, NULL);
00312 }
00313 
00314 static void
00315 gnc_plugin_page_report_finalize (GObject *object)
00316 {
00317     GncPluginPageReport *page;
00318     GncPluginPageReportPrivate *priv;
00319 
00320     g_return_if_fail (GNC_IS_PLUGIN_PAGE_REPORT (object));
00321 
00322     ENTER("object %p", object);
00323     page = GNC_PLUGIN_PAGE_REPORT (object);
00324     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(page);
00325 
00326     G_OBJECT_CLASS (parent_class)->finalize (object);
00327     LEAVE(" ");
00328 }
00329 
00330 static
00331 GtkWidget*
00332 gnc_plugin_page_report_create_widget( GncPluginPage *page )
00333 {
00334     GncPluginPageReport *report;
00335     GncPluginPageReportPrivate *priv;
00336     GtkWindow *topLvl;
00337     URLType type;
00338     char * id_name;
00339     char * child_name;
00340     char * url_location = NULL;
00341     char * url_label = NULL;
00342 
00343     ENTER("page %p", page);
00344 
00345     report = GNC_PLUGIN_PAGE_REPORT(page);
00346     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
00347 
00348     topLvl = GTK_WINDOW(gnc_ui_get_toplevel());
00349 //        priv->html = gnc_html_new( topLvl );
00350     priv->html = gnc_html_factory_create_html();
00351     gnc_html_set_parent( priv->html, topLvl );
00352 
00353     gnc_html_history_set_node_destroy_cb(gnc_html_get_history(priv->html),
00354                                          gnc_plugin_page_report_history_destroy_cb,
00355                                          (gpointer)priv);
00356 
00357     priv->container = GTK_CONTAINER(gtk_frame_new(NULL));
00358     gtk_frame_set_shadow_type(GTK_FRAME(priv->container), GTK_SHADOW_NONE);
00359 
00360     gtk_container_add(GTK_CONTAINER(priv->container),
00361                       gnc_html_get_widget(priv->html));
00362 
00363     priv->component_manager_id =
00364         gnc_register_gui_component(WINDOW_REPORT_CM_CLASS, NULL,
00365                                    close_handler, page);
00366     gnc_gui_component_set_session(priv->component_manager_id,
00367                                   gnc_get_current_session());
00368 
00369     gnc_html_set_urltype_cb(priv->html, gnc_plugin_page_report_check_urltype);
00370     gnc_html_set_load_cb(priv->html, gnc_plugin_page_report_load_cb, report);
00371 
00372     // FIXME.  This is f^-1(f(x)), isn't it?
00373     DEBUG( "id=%d", priv->reportId );
00374     id_name = g_strdup_printf("id=%d", priv->reportId );
00375     child_name = gnc_build_url( URL_TYPE_REPORT, id_name, NULL );
00376     type = gnc_html_parse_url( priv->html, child_name, &url_location, &url_label);
00377     DEBUG( "passing id_name=[%s] child_name=[%s] type=[%s], location=[%s], label=[%s]",
00378            id_name, child_name ? child_name : "(null)",
00379            type ? type : "(null)", url_location ? url_location : "(null)",
00380            url_label ? url_label : "(null)" );
00381 
00382     g_free(id_name);
00383     g_free(child_name);
00384     gnc_window_set_progressbar_window( GNC_WINDOW(page->window) );
00385     gnc_html_show_url(priv->html, type, url_location, url_label, 0);
00386     g_free(url_location);
00387     gnc_window_set_progressbar_window( NULL );
00388 
00389     g_signal_connect(priv->container, "expose_event",
00390                      G_CALLBACK(gnc_plugin_page_report_expose_event_cb), report);
00391 
00392     gtk_widget_show_all( GTK_WIDGET(priv->container) );
00393 
00394     LEAVE("container %p", priv->container);
00395 
00396     return GTK_WIDGET( priv->container );
00397 }
00398 
00399 /********************************************************************
00400  * gnc_plugin_page_report_check_urltype
00401  * is it OK to show a certain URLType in this window?
00402  ********************************************************************/
00403 static int
00404 gnc_plugin_page_report_check_urltype(URLType t)
00405 {
00406     if (!safe_strcmp (t, URL_TYPE_REPORT))
00407     {
00408         return TRUE;
00409     }
00410     else
00411     {
00412         return FALSE;
00413     }
00414 }
00415 
00420 static void
00421 gnc_plugin_page_report_setup( GncPluginPage *ppage )
00422 {
00423     GncPluginPageReport *report = GNC_PLUGIN_PAGE_REPORT(ppage);
00424     GncPluginPageReportPrivate *priv;
00425     SCM  set_needs_save = scm_c_eval_string("gnc:report-set-needs-save?!");
00426     SCM  inst_report;
00427     int  report_id;
00428 
00429     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
00430     priv->cur_report        = SCM_BOOL_F;
00431     priv->initial_report    = SCM_BOOL_F;
00432     priv->edited_reports    = SCM_EOL;
00433     priv->name_change_cb_id = SCM_BOOL_F;
00434 
00435     g_object_get( ppage, "report-id", &report_id, NULL );
00436 
00437     PINFO("report-id: %d\n", report_id);
00438 
00439     /* get the inst-report from the Scheme-side hash, and get its
00440      * options and editor thunk */
00441     if ((inst_report = gnc_report_find(report_id)) == SCM_BOOL_F)
00442     {
00443         return;
00444     }
00445 
00446     if (priv->initial_report == SCM_BOOL_F)
00447     {
00448         priv->initial_report = inst_report;
00449         scm_gc_protect_object(priv->initial_report);
00450     }
00451 
00452     // all reports need [to be] saved immediately after they're created.
00453     PINFO("set needs save");
00454     scm_call_2(set_needs_save, inst_report, SCM_BOOL_T);
00455 }
00456 
00457 /********************************************************************
00458  * gnc_plugin_page_report_load_cb
00459  * called after a report is loaded into the gnc_html widget
00460  ********************************************************************/
00461 static void
00462 //gnc_plugin_page_report_load_cb(gnc_html * html, URLType type,
00463 gnc_plugin_page_report_load_cb(GncHtml * html, URLType type,
00464                                const gchar * location, const gchar * label,
00465                                gpointer data)
00466 {
00467     GncPluginPageReport *report = GNC_PLUGIN_PAGE_REPORT(data);
00468     GncPluginPageReportPrivate *priv;
00469     int  report_id;
00470     SCM  get_options    = scm_c_eval_string("gnc:report-options");
00471     SCM  set_needs_save = scm_c_eval_string("gnc:report-set-needs-save?!");
00472     SCM  inst_report;
00473 
00474     ENTER( "load_cb: type=[%s], location=[%s], label=[%s]",
00475            type ? type : "(null)", location ? location : "(null)",
00476            label ? label : "(null)" );
00477 
00478     /* we get this callback if a new report is requested to be loaded OR
00479      * if any URL is clicked.  If an options URL is clicked, we want to
00480      * know about it */
00481     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
00482     if (!safe_strcmp (type, URL_TYPE_REPORT)
00483             && location
00484             && (strlen(location) > 3)
00485             && !strncmp("id=", location, 3))
00486     {
00487         report_id = atoi(location + 3);
00488         DEBUG( "parsed id=%d", report_id );
00489     }
00490     else if (!safe_strcmp( type, URL_TYPE_OPTIONS)
00491              && location
00492              && (strlen(location) > 10)
00493              && !strncmp("report-id=", location, 10))
00494     {
00495         report_id = atoi(location + 10);
00496         inst_report = gnc_report_find(report_id);
00497         if (inst_report != SCM_BOOL_F)
00498         {
00499             gnc_plugin_page_report_add_edited_report(priv, inst_report);
00500         }
00501         LEAVE("");
00502         return;
00503     }
00504     else
00505     {
00506         LEAVE( " unknown URL type [%s] location [%s]", type, location );
00507         return;
00508     }
00509 
00510     /* get the inst-report from the hash, and get its
00511      * options and editor thunk */
00512     if ((inst_report = gnc_report_find(report_id)) == SCM_BOOL_F)
00513     {
00514         LEAVE( "error getting inst_report" );
00515         return;
00516     }
00517 
00518     if (priv->initial_report == SCM_BOOL_F)
00519     {
00520         priv->initial_report = inst_report;
00521         scm_gc_protect_object(priv->initial_report);
00522 
00523         DEBUG("calling set_needs_save for report with id=%d", report_id);
00524         scm_call_2(set_needs_save, inst_report, SCM_BOOL_T);
00525 
00526         priv->initial_odb = gnc_option_db_new(scm_call_1(get_options, inst_report));
00527         priv->name_change_cb_id =
00528             gnc_option_db_register_change_callback(priv->initial_odb,
00529                     gnc_plugin_page_report_refresh,
00530                     priv,
00531                     "General", "Report name");
00532     }
00533 
00534     if ((priv->cur_report != SCM_BOOL_F) && (priv->cur_odb != NULL))
00535     {
00536         gnc_option_db_unregister_change_callback_id(priv->cur_odb,
00537                 priv->option_change_cb_id);
00538         gnc_option_db_destroy(priv->cur_odb);
00539         priv->cur_odb = NULL;
00540     }
00541 
00542     if (priv->cur_report != SCM_BOOL_F)
00543         scm_gc_unprotect_object(priv->cur_report);
00544     priv->cur_report = inst_report;
00545     scm_gc_protect_object(priv->cur_report);
00546 
00547     priv->cur_odb = gnc_option_db_new(scm_call_1(get_options, inst_report));
00548     priv->option_change_cb_id =
00549         gnc_option_db_register_change_callback(priv->cur_odb,
00550                 gnc_plugin_page_report_option_change_cb,
00551                 report, NULL, NULL);
00552 
00553     if (gnc_html_history_forward_p(gnc_html_get_history(priv->html)))
00554     {
00555         gnc_plugin_page_report_set_fwd_button(report, TRUE);
00556     }
00557     else
00558     {
00559         gnc_plugin_page_report_set_fwd_button(report, FALSE);
00560     }
00561 
00562     if (gnc_html_history_back_p(gnc_html_get_history(priv->html)))
00563     {
00564         gnc_plugin_page_report_set_back_button(report, TRUE);
00565     }
00566     else
00567     {
00568         gnc_plugin_page_report_set_back_button(report, FALSE);
00569     }
00570 
00571     LEAVE( "done" );
00572 }
00573 
00574 
00586 static void
00587 gnc_plugin_page_report_option_change_cb(gpointer data)
00588 {
00589     GncPluginPageReport *report;
00590     GncPluginPageReportPrivate *priv;
00591     GtkActionGroup *action_group;
00592     GtkAction *action;
00593     SCM dirty_report = scm_c_eval_string("gnc:report-set-dirty?!");
00594     const gchar *old_name;
00595     gchar *new_name;
00596 
00597     g_return_if_fail(GNC_IS_PLUGIN_PAGE_REPORT(data));
00598     report = GNC_PLUGIN_PAGE_REPORT(data);
00599     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
00600 
00601     DEBUG( "option_change" );
00602     if (priv->cur_report == SCM_BOOL_F)
00603         return;
00604     DEBUG( "set-dirty, queue-draw" );
00605 
00606     /* Update the page (i.e. the notebook tab and window title) */
00607     old_name = gnc_plugin_page_get_page_name(GNC_PLUGIN_PAGE(report));
00608     new_name = gnc_option_db_lookup_string_option(priv->cur_odb, "General",
00609                "Report name", NULL);
00610     if (strcmp(old_name, new_name) != 0)
00611     {
00612         main_window_update_page_name(GNC_PLUGIN_PAGE(report), new_name);
00613         action_group = gnc_plugin_page_get_action_group(GNC_PLUGIN_PAGE(report));
00614         action = gtk_action_group_get_action (action_group, "ReportSaveAction");
00615         gtk_action_set_sensitive(action, TRUE);
00616     }
00617     g_free(new_name);
00618 
00619     /* it's probably already dirty, but make sure */
00620     scm_call_2(dirty_report, priv->cur_report, SCM_BOOL_T);
00621 
00622     /* Now queue the fact that we need to reload this report */
00623     priv->need_reload = TRUE;
00624     // jsled: this doesn't seem to cause any effect.
00625     gtk_widget_queue_draw( GTK_WIDGET(priv->container) );
00626     // jsled: this does.
00627     gnc_html_reload( priv->html );
00628 }
00629 
00630 /* FIXME: This function does... nothing.  */
00631 static void
00632 gnc_plugin_page_report_history_destroy_cb(gnc_html_history_node * node,
00633         gpointer user_data)
00634 {
00635 #if 0
00636     static SCM         remover = SCM_BOOL_F;
00637     int                report_id;
00638 
00639     if (remover == SCM_BOOL_F)
00640     {
00641         remover = scm_c_eval_string("gnc:report-remove-by-id");
00642     }
00643 
00644     if (node
00645             && !safe_strcmp (node->type, URL_TYPE_REPORT)\
00646             && !strncmp("id=", node->location, 3))
00647     {
00648         sscanf(node->location + 3, "%d", &report_id);
00649         /*    printf("unreffing report %d and children\n", report_id);
00650               scm_call_1(remover, scm_int2num(report_id)); */
00651     }
00652     else
00653     {
00654         return;
00655     }
00656 #endif
00657 }
00658 
00659 /* We got a draw event.  See if we need to reload the report */
00660 static void
00661 gnc_plugin_page_report_expose_event_cb(GtkWidget *unused, GdkEventExpose *unused1, gpointer data)
00662 {
00663     GncPluginPageReport *page = data;
00664     GncPluginPageReportPrivate *priv;
00665 
00666     g_return_if_fail(GNC_IS_PLUGIN_PAGE_REPORT(page));
00667 
00668     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(page);
00669     ENTER( "report_draw" );
00670     if (!priv->need_reload)
00671     {
00672         LEAVE( "no reload needed" );
00673         return;
00674     }
00675 
00676     priv->need_reload = FALSE;
00677     gnc_window_set_progressbar_window( GNC_WINDOW(GNC_PLUGIN_PAGE(page)->window) );
00678     gnc_html_reload(priv->html);
00679     gnc_window_set_progressbar_window( NULL );
00680     LEAVE( "reload forced" );
00681 }
00682 
00683 // @param data is actually GncPluginPageReportPrivate
00684 static void
00685 gnc_plugin_page_report_refresh(gpointer data)
00686 {
00687     // FIXME?
00688     DEBUG( "report-refresh called" );
00689     // something like ... gnc_plugin_page_report_redraw( NULL, (GncPluginPageReportPrivate*)data );
00690     return;
00691 }
00692 
00693 static void
00694 gnc_plugin_page_report_destroy_widget(GncPluginPage *plugin_page)
00695 {
00696     GncPluginPageReportPrivate *priv;
00697 
00698     // FIXME: cleanup other resources.
00699 
00700     PINFO("destroy widget");
00701     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(plugin_page);
00702 
00703     if (priv->component_manager_id)
00704     {
00705         gnc_unregister_gui_component(priv->component_manager_id);
00706         priv->component_manager_id = 0;
00707     }
00708 
00709     gnc_plugin_page_report_destroy(priv);
00710     gnc_report_remove_by_id(priv->reportId);
00711 }
00712 
00713 
00716 #define SCHEME_OPTIONS   "SchemeOptions"
00717 #define SCHEME_OPTIONS_N "SchemeOptions%d"
00718 
00719 
00729 static void
00730 gnc_plugin_page_report_save_page (GncPluginPage *plugin_page,
00731                                   GKeyFile *key_file,
00732                                   const gchar *group_name)
00733 {
00734     GncPluginPageReport *report;
00735     GncPluginPageReportPrivate *priv;
00736     SCM gen_save_text, scm_text;
00737     SCM get_embedded_list, embedded, item, tmp_report;
00738     gint count, id;
00739     gchar *text, *key_name;
00740     char * str;
00741 
00742     g_return_if_fail (GNC_IS_PLUGIN_PAGE_REPORT(plugin_page));
00743     g_return_if_fail (key_file != NULL);
00744     g_return_if_fail (group_name != NULL);
00745 
00746     ENTER("page %p, key_file %p, group_name %s", plugin_page, key_file,
00747           group_name);
00748 
00749     report = GNC_PLUGIN_PAGE_REPORT(plugin_page);
00750     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
00751 
00752     if (!priv || !priv->cur_report || scm_is_null(priv->cur_report) ||
00753             SCM_UNBNDP(priv->cur_report) || SCM_BOOL_F == priv->cur_report)
00754     {
00755         LEAVE("not saving invalid report");
00756         return;
00757     }
00758 
00759     gen_save_text = scm_c_eval_string("gnc:report-generate-restore-forms");
00760     get_embedded_list = scm_c_eval_string("gnc:report-embedded-list");
00761     embedded = scm_call_1(get_embedded_list, priv->cur_report);
00762     count = scm_ilength(embedded);
00763     while (count-- > 0)
00764     {
00765         item = SCM_CAR(embedded);
00766         embedded = SCM_CDR(embedded);
00767         if (!scm_is_number(item))
00768             continue;
00769         id = SCM_INUM(item);
00770         tmp_report = gnc_report_find(id);
00771         scm_text = scm_call_1(gen_save_text, tmp_report);
00772         if (!scm_is_string (scm_text))
00773         {
00774             DEBUG("child report %d: nothing to save", id);
00775             continue;
00776         }
00777 
00778         key_name = g_strdup_printf(SCHEME_OPTIONS_N, id);
00779         scm_dynwind_begin (0);
00780         str = scm_to_locale_string (scm_text);
00781         text = gnc_guile_strip_comments(str);
00782         g_key_file_set_string(key_file, group_name, key_name, text);
00783         g_free(text);
00784         scm_dynwind_free (str);
00785         scm_dynwind_end ();
00786         g_free(key_name);
00787     }
00788 
00789     scm_text = scm_call_1(gen_save_text, priv->cur_report);
00790     if (!scm_is_string (scm_text))
00791     {
00792         LEAVE("nothing to save");
00793         return;
00794     }
00795 
00796     scm_dynwind_begin (0);
00797     str = scm_to_locale_string (scm_text);
00798     text = gnc_guile_strip_comments(str);
00799     g_key_file_set_string(key_file, group_name, SCHEME_OPTIONS, text);
00800     g_free(text);
00801     scm_dynwind_free (str);
00802     scm_dynwind_end ();
00803     LEAVE(" ");
00804 }
00805 
00806 
00816 static GncPluginPage *
00817 gnc_plugin_page_report_recreate_page (GtkWidget *window,
00818                                       GKeyFile *key_file,
00819                                       const gchar *group_name)
00820 {
00821     GncPluginPage *page;
00822     gchar **keys;
00823     gsize i, num_keys;
00824     GError *error = NULL;
00825     gchar *option_string;
00826     gint report_id;
00827     SCM scm_id, final_id = SCM_BOOL_F;
00828     SCM report;
00829 
00830     g_return_val_if_fail(key_file, NULL);
00831     g_return_val_if_fail(group_name, NULL);
00832     ENTER("key_file %p, group_name %s", key_file, group_name);
00833 
00834     keys = g_key_file_get_keys(key_file, group_name, &num_keys, &error);
00835     if (error)
00836     {
00837         g_warning("error reading group %s key list: %s",
00838                   group_name, error->message);
00839         g_error_free(error);
00840         LEAVE("no keys");
00841         return NULL;
00842     }
00843 
00844     for (i = 0; i < num_keys; i++)
00845     {
00846         if (strncmp(keys[i], SCHEME_OPTIONS, strlen(SCHEME_OPTIONS)) != 0)
00847             continue;
00848         option_string = g_key_file_get_string(key_file, group_name,
00849                                               keys[i], &error);
00850         if (error)
00851         {
00852             g_warning("error reading group %s key %s: %s",
00853                       group_name, keys[i], error->message);
00854             g_error_free(error);
00855             LEAVE("bad value");
00856             return NULL;
00857         }
00858 
00859         scm_id = scm_c_eval_string(option_string);
00860         g_free(option_string);
00861 
00862         if (!scm_integer_p(scm_id))
00863         {
00864             DEBUG("report id not an integer for key %s", keys[i]);
00865             return NULL;
00866         }
00867 
00868         if (final_id == SCM_BOOL_F)
00869         {
00870             if (strcmp(keys[i], SCHEME_OPTIONS) == 0)
00871             {
00872                 final_id = scm_id;
00873             }
00874         }
00875     }
00876 
00877     if (final_id == SCM_BOOL_F)
00878     {
00879         LEAVE("report not specified");
00880         return NULL;
00881     }
00882 
00883     report_id = scm_num2int(final_id, SCM_ARG1, G_STRFUNC);
00884     report = gnc_report_find(report_id);
00885     if (!report)
00886     {
00887         LEAVE("report doesn't exist");
00888         return NULL;
00889     }
00890 
00891     page = gnc_plugin_page_report_new( report_id );
00892 
00893     LEAVE(" ");
00894     return page;
00895 }
00896 
00897 
00908 static void
00909 gnc_plugin_page_report_name_changed (GncPluginPage *page, const gchar *name)
00910 {
00911     GncPluginPageReportPrivate *priv;
00912     GtkActionGroup *action_group;
00913     GtkAction *action;
00914     static gint count = 1, max_count = 10;
00915     const gchar *old_name;
00916 
00917     g_return_if_fail(GNC_IS_PLUGIN_PAGE_REPORT(page));
00918     g_return_if_fail(name != NULL);
00919     g_return_if_fail(count++ <= max_count);
00920 
00921     ENTER("page %p, name %s", page, name);
00922     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(page);
00923 
00924     /* Is this a redundant call? */
00925     old_name = gnc_option_db_lookup_string_option(priv->cur_odb, "General",
00926                "Report name", NULL);
00927     DEBUG("Comparing old name '%s' to new name '%s'",
00928           old_name ? old_name : "(null)", name);
00929     if (old_name && (strcmp(old_name, name) == 0))
00930     {
00931         LEAVE("no change");
00932         return;
00933     }
00934 
00935     /* Store the new name for the report. */
00936     gnc_option_db_set_string_option(priv->cur_odb, "General",
00937                                     "Report name", name);
00938 
00939     /* Have to manually call the option change hook. */
00940     gnc_plugin_page_report_option_change_cb(page);
00941 
00942     /* Careful. This is called at report construction time. */
00943     action_group = gnc_plugin_page_get_action_group(page);
00944     if (action_group)
00945     {
00946         /* Allow the user to save the report now. */
00947         action = gtk_action_group_get_action (action_group, "ReportSaveAction");
00948         gtk_action_set_sensitive(action, TRUE);
00949     }
00950     LEAVE(" ");
00951 }
00952 
00953 static void
00954 gnc_plugin_page_report_update_edit_menu (GncPluginPage *page, gboolean hide)
00955 {
00956     GtkAction *action;
00957 
00958     action = gnc_plugin_page_get_action (page, "EditCopyAction");
00959     gtk_action_set_sensitive (action, TRUE);
00960     gtk_action_set_visible (action, TRUE);
00961     action = gnc_plugin_page_get_action (page, "EditCutAction");
00962     gtk_action_set_sensitive (action, FALSE);
00963     gtk_action_set_visible (action, !hide);
00964     action = gnc_plugin_page_get_action (page, "EditPasteAction");
00965     gtk_action_set_sensitive (action, FALSE);
00966     gtk_action_set_visible (action, !hide);
00967 }
00968 
00969 static gboolean
00970 gnc_plugin_page_report_finish_pending (GncPluginPage *page)
00971 {
00972     GncPluginPageReportPrivate *priv;
00973     GncPluginPageReport *report;
00974 
00975     report = GNC_PLUGIN_PAGE_REPORT(page);
00976     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
00977     return !priv->reloading;
00978 }
00979 
00980 
00981 /********************************************************************
00982  * gnc_report_window_destroy
00983  * free and destroy a window
00984  ********************************************************************/
00985 void
00986 gnc_plugin_page_report_destroy(GncPluginPageReportPrivate * priv)
00987 {
00988     SCM  get_editor = scm_c_eval_string("gnc:report-editor-widget");
00989     SCM  set_editor = scm_c_eval_string("gnc:report-set-editor-widget!");
00990     SCM  edited, editor;
00991 
00992     /* close any open editors */
00993     for (edited = scm_list_copy(priv->edited_reports); !scm_is_null(edited);
00994             edited = SCM_CDR(edited))
00995     {
00996         editor = scm_call_1(get_editor, SCM_CAR(edited));
00997         scm_call_2(set_editor, SCM_CAR(edited), SCM_BOOL_F);
00998         if (editor != SCM_BOOL_F)
00999         {
01000             GtkWidget *w = NULL;
01001 #define FUNC_NAME "gtk_widget_destroy"
01002             w = SWIG_MustGetPtr(editor,
01003                                 SWIG_TypeQuery("_p_GtkWidget"), 1, 0);
01004 #undef FUNC_NAME
01005             gtk_widget_destroy(GTK_WIDGET(w));
01006         }
01007     }
01008 
01009     if (priv->initial_odb)
01010     {
01011         gnc_option_db_unregister_change_callback_id(priv->initial_odb,
01012                 priv->name_change_cb_id);
01013 
01014         gnc_option_db_destroy(priv->initial_odb);
01015         priv->initial_odb = NULL;
01016     }
01017 
01018     gnc_html_destroy(priv->html);
01019 
01020     priv->container     = NULL;
01021     priv->html          = NULL;
01022 
01023     if (priv->cur_report != SCM_BOOL_F)
01024         scm_gc_unprotect_object(priv->cur_report);
01025     if (priv->edited_reports != SCM_EOL)
01026         scm_gc_unprotect_object(priv->edited_reports);
01027 }
01028 
01029 static GtkActionEntry report_actions[] =
01030 {
01031     {
01032         "FilePrintAction", GTK_STOCK_PRINT, N_("_Print Report..."), "<control>p",
01033         N_("Print the current report"),
01034         G_CALLBACK(gnc_plugin_page_report_print_cb)
01035     },
01036     {
01037         "FilePrintPDFAction", GNC_STOCK_PDF_EXPORT, N_("Export as P_DF..."), NULL,
01038         N_("Export the current report as a PDF document"),
01039         G_CALLBACK(gnc_plugin_page_report_exportpdf_cb)
01040     },
01041     {
01042         "EditCutAction", GTK_STOCK_CUT, N_("Cu_t"), NULL,
01043         N_("Cut the current selection and copy it to clipboard"),
01044         NULL
01045     },
01046     {
01047         "EditCopyAction", GTK_STOCK_COPY, N_("_Copy"), NULL,
01048         N_("Copy the current selection to clipboard"),
01049         G_CALLBACK(gnc_plugin_page_report_copy_cb)
01050     },
01051     {
01052         "EditPasteAction", GTK_STOCK_PASTE, N_("_Paste"), NULL,
01053         N_("Paste the clipboard content at the cursor position"),
01054         NULL
01055     },
01056     {
01057         "ViewRefreshAction", GTK_STOCK_REFRESH, N_("_Refresh"), "<control>r",
01058         N_("Refresh this window"),
01059         G_CALLBACK (gnc_plugin_page_report_reload_cb)
01060     },
01061     {
01062         "ReportSaveAction", GTK_STOCK_SAVE, N_("Add _Report"), "",
01063         N_("Add the current report to the `Custom' menu for later use. "
01064         "The report will be saved in the file ~/.gnucash/saved-reports-2.4. "
01065         "It will be accessible as menu entry in the report menu at the "
01066         "next startup of GnuCash."),
01067         G_CALLBACK(gnc_plugin_page_report_save_cb)
01068     },
01069     {
01070         "ReportExportAction", GTK_STOCK_CONVERT, N_("Export _Report"), NULL,
01071         N_("Export HTML-formatted report to file"),
01072         G_CALLBACK(gnc_plugin_page_report_export_cb)
01073     },
01074     {
01075         "ReportOptionsAction", GTK_STOCK_PROPERTIES, N_("_Report Options"), NULL,
01076         N_("Edit report options"),
01077         G_CALLBACK(gnc_plugin_page_report_options_cb)
01078     },
01079 
01080     {
01081         "ReportBackAction", GTK_STOCK_GO_BACK, N_("Back"), NULL,
01082         N_("Move back one step in the history"),
01083         G_CALLBACK(gnc_plugin_page_report_back_cb)
01084     },
01085     {
01086         "ReportForwAction", GTK_STOCK_GO_FORWARD, N_("Forward"), NULL,
01087         N_("Move forward one step in the history"),
01088         G_CALLBACK(gnc_plugin_page_report_forw_cb)
01089     },
01090     {
01091         "ReportReloadAction", GTK_STOCK_REFRESH, N_("Reload"), NULL,
01092         N_("Reload the current page"),
01093         G_CALLBACK(gnc_plugin_page_report_reload_cb)
01094     },
01095     {
01096         "ReportStopAction", GTK_STOCK_STOP, N_("Stop"), NULL,
01097         N_("Cancel outstanding HTML requests"),
01098         G_CALLBACK(gnc_plugin_page_report_stop_cb)
01099     },
01100 };
01101 static guint num_report_actions = G_N_ELEMENTS( report_actions );
01102 
01104 static action_toolbar_labels toolbar_labels[] =
01105 {
01106     { "FilePrintAction",            N_("Print") },
01107     { "ReportExportAction",   N_("Export") },
01108     { "ReportOptionsAction",  N_("Options") },
01109     { NULL, NULL },
01110 };
01111 
01112 static const gchar *initially_insensitive_actions[] =
01113 {
01114     "ReportSaveAction",
01115     NULL
01116 };
01117 
01118 static void
01119 gnc_plugin_page_report_init ( GncPluginPageReport *plugin_page )
01120 {
01121 }
01122 
01123 static GObject*
01124 gnc_plugin_page_report_constructor(GType this_type, guint n_properties, GObjectConstructParam *properties)
01125 {
01126     GObject *obj;
01127     GncPluginPageReportClass *our_class;
01128     GObjectClass *parent_class;
01129     gint reportId = -42;
01130     int i;
01131 
01132     our_class = GNC_PLUGIN_PAGE_REPORT_CLASS (
01133                     g_type_class_peek (GNC_TYPE_PLUGIN_PAGE_REPORT));
01134     parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (our_class));
01135     obj = parent_class->constructor(this_type, n_properties, properties);
01136 
01137     for (i = 0; i < n_properties; i++)
01138     {
01139         GObjectConstructParam prop = properties[i];
01140         if (strcmp(prop.pspec->name, "report-id") == 0)
01141         {
01142             reportId = g_value_get_int(prop.value);
01143         }
01144     }
01145 
01146     gnc_plugin_page_report_constr_init(GNC_PLUGIN_PAGE_REPORT(obj), reportId);
01147 
01148     return obj;
01149 }
01150 
01151 static void
01152 gnc_plugin_page_report_constr_init(GncPluginPageReport *plugin_page, gint reportId)
01153 {
01154     GncPluginPageReportPrivate *priv;
01155     GtkActionGroup *action_group;
01156     GncPluginPage *parent;
01157     gboolean use_new;
01158     gchar *name;
01159 
01160     DEBUG( "property reportId=%d", reportId );
01161     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(plugin_page);
01162     priv->reportId = reportId;
01163 
01164     gnc_plugin_page_report_setup( GNC_PLUGIN_PAGE(plugin_page) );
01165 
01166     /* Init parent declared variables */
01167     parent = GNC_PLUGIN_PAGE(plugin_page);
01168     use_new = gnc_gconf_get_bool(GCONF_GENERAL_REPORT, KEY_USE_NEW, NULL);
01169     name = gnc_report_name( priv->initial_report );
01170     g_object_set(G_OBJECT(plugin_page),
01171                  "page-name",      name,
01172                  "page-uri",       "default:",
01173                  "ui-description", "gnc-plugin-page-report-ui.xml",
01174                  "use-new-window", use_new,
01175                  NULL);
01176     g_free(name);
01177 
01178     /* change me when the system supports multiple books */
01179     gnc_plugin_page_add_book(parent, gnc_get_current_book());
01180 
01181     /* Create menu and toolbar information */
01182     action_group =
01183         gnc_plugin_page_create_action_group(parent,
01184                                             "GncPluginPageReportActions");
01185     gtk_action_group_add_actions( action_group,
01186                                   report_actions,
01187                                   num_report_actions,
01188                                   plugin_page );
01189     gnc_plugin_update_actions(action_group,
01190                               initially_insensitive_actions,
01191                               "sensitive", FALSE);
01192     gnc_plugin_init_short_names (action_group, toolbar_labels);
01193 }
01194 
01195 GncPluginPage*
01196 gnc_plugin_page_report_new( int reportId )
01197 {
01198     GncPluginPageReport *plugin_page;
01199 
01200     DEBUG( "report id = %d", reportId );
01201     plugin_page = g_object_new( GNC_TYPE_PLUGIN_PAGE_REPORT,
01202                                 "report-id", reportId, NULL );
01203     DEBUG( "plugin_page: %p", plugin_page );
01204     DEBUG( "set %d on page %p", reportId, plugin_page );
01205     return GNC_PLUGIN_PAGE( plugin_page );
01206 }
01207 
01208 void
01209 gnc_plugin_page_report_remove_edited_report(GncPluginPageReportPrivate *priv,
01210         SCM report)
01211 {
01212     SCM new_edited = scm_delete(priv->edited_reports, report);
01213     if (priv->edited_reports != SCM_EOL)
01214         scm_gc_unprotect_object(priv->edited_reports);
01215     priv->edited_reports = new_edited;
01216     if (new_edited != SCM_EOL)
01217         scm_gc_protect_object(priv->edited_reports);
01218 }
01219 
01220 void
01221 gnc_plugin_page_report_add_edited_report(GncPluginPageReportPrivate *priv,
01222         SCM report)
01223 {
01224     SCM new_edited = scm_cons(report, priv->edited_reports);
01225     if (priv->edited_reports != SCM_EOL)
01226         scm_gc_unprotect_object(priv->edited_reports);
01227     priv->edited_reports = new_edited;
01228     if (new_edited != SCM_EOL)
01229         scm_gc_protect_object(priv->edited_reports);
01230 }
01231 
01232 void
01233 gnc_plugin_page_report_raise_editor(SCM report)
01234 {
01235     SCM get_editor = scm_c_eval_string("gnc:report-editor-widget");
01236     SCM editor = scm_call_1(get_editor, report);
01237 #define FUNC_NAME "gtk_window_present"
01238     GtkWidget *w = SWIG_MustGetPtr(editor,
01239                                    SWIG_TypeQuery("_p_GtkWidget"), 1, 0);
01240 #undef FUNC_NAME
01241     gtk_window_present(GTK_WINDOW(w));
01242 }
01243 
01244 static void
01245 close_handler (gpointer user_data)
01246 {
01247     GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(user_data);
01248     DEBUG("in close handler\n");
01249     gnc_main_window_close_page (plugin_page);
01250 }
01251 
01252 static void
01253 gnc_plugin_page_report_set_fwd_button(GncPluginPageReport *report, int enabled)
01254 {
01255     GtkAction *act;
01256 
01257     act = gnc_plugin_page_get_action(GNC_PLUGIN_PAGE(report),
01258                                      "ReportForwAction" );
01259     gtk_action_set_sensitive(act, enabled);
01260 }
01261 
01262 static void
01263 gnc_plugin_page_report_set_back_button(GncPluginPageReport *report, int enabled)
01264 {
01265     GtkAction *act;
01266 
01267     act = gnc_plugin_page_get_action(GNC_PLUGIN_PAGE(report),
01268                                      "ReportBackAction" );
01269     gtk_action_set_sensitive(act, enabled);
01270 }
01271 
01272 // ------------------------------------------------------------
01273 // GTK ACTION CALLBACKS
01274 
01275 static void
01276 gnc_plugin_page_report_forw_cb( GtkAction *action, GncPluginPageReport *report )
01277 {
01278     GncPluginPageReportPrivate *priv;
01279     gnc_html_history_node * node = NULL;
01280 
01281     DEBUG( "forw" );
01282     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
01283     gnc_html_history_forward(gnc_html_get_history(priv->html));
01284     node = gnc_html_history_get_current(gnc_html_get_history(priv->html));
01285     if (node)
01286     {
01287         gnc_html_show_url(priv->html, node->type, node->location,
01288                           node->label, 0);
01289     }
01290 }
01291 
01292 static void
01293 gnc_plugin_page_report_back_cb( GtkAction *action, GncPluginPageReport *report )
01294 {
01295     GncPluginPageReportPrivate *priv;
01296     gnc_html_history_node * node;
01297 
01298     DEBUG( "back" );
01299     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
01300     gnc_html_history_back(gnc_html_get_history(priv->html));
01301     node = gnc_html_history_get_current(gnc_html_get_history(priv->html));
01302     if (node)
01303     {
01304         gnc_html_show_url(priv->html, node->type, node->location,
01305                           node->label, 0);
01306     }
01307 }
01308 
01309 static void
01310 gnc_plugin_page_report_reload_cb( GtkAction *action, GncPluginPageReport *report )
01311 {
01312     GncPluginPageReportPrivate *priv;
01313     SCM dirty_report;
01314 
01315     DEBUG( "reload" );
01316     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
01317     if (priv->cur_report == SCM_BOOL_F)
01318         return;
01319 
01320     DEBUG( "reload-redraw" );
01321     dirty_report = scm_c_eval_string("gnc:report-set-dirty?!");
01322     scm_call_2(dirty_report, priv->cur_report, SCM_BOOL_T);
01323 
01324     priv->need_reload = TRUE;
01325     /* now queue the fact that we need to reload this report */
01326 
01327     // this doens't seem to do anything...
01328     gtk_widget_queue_draw( GTK_WIDGET(priv->container) );
01329 
01330     // this does...
01331     priv->reloading = TRUE;
01332     gnc_html_reload( priv->html );
01333     priv->reloading = FALSE;
01334 }
01335 
01336 static void
01337 gnc_plugin_page_report_stop_cb( GtkAction *action, GncPluginPageReport *report )
01338 {
01339     GncPluginPageReportPrivate *priv;
01340 
01341     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
01342     gnc_html_cancel(priv->html);
01343 }
01344 
01345 /* Returns SCM_BOOL_F if cancel. Returns SCM_BOOL_T if html.
01346  * Otherwise returns pair from export_types. */
01347 static SCM
01348 gnc_get_export_type_choice (SCM export_types)
01349 {
01350     GList * choices = NULL;
01351     gboolean bad = FALSE;
01352     GList * node;
01353     int choice;
01354     SCM tail;
01355 
01356     if (!scm_is_list (export_types))
01357         return SCM_BOOL_F;
01358 
01359     for (tail = export_types; !scm_is_null (tail); tail = SCM_CDR (tail))
01360     {
01361         SCM pair = SCM_CAR (tail);
01362         char * name;
01363         SCM scm;
01364 
01365         if (!scm_is_pair (pair))
01366         {
01367             g_warning ("unexpected list element");
01368             bad = TRUE;
01369             break;
01370         }
01371 
01372         scm = SCM_CAR (pair);
01373         if (!scm_is_string (scm))
01374         {
01375             g_warning ("unexpected pair element");
01376             bad = TRUE;
01377             break;
01378         }
01379 
01380         scm_dynwind_begin (0);
01381         name = scm_to_locale_string (scm);
01382         choices = g_list_prepend (choices, g_strdup (name));
01383         scm_dynwind_free (name);
01384         scm_dynwind_end ();
01385     }
01386 
01387     if (!bad)
01388     {
01389         choices = g_list_reverse (choices);
01390 
01391         choices = g_list_prepend (choices, g_strdup (_("HTML")));
01392 
01393         choice = gnc_choose_radio_option_dialog
01394                  (NULL, _("Choose export format"),
01395                   _("Choose the export format for this report:"),
01396                   NULL, 0, choices);
01397     }
01398     else
01399         choice = -1;
01400 
01401     for (node = choices; node; node = node->next)
01402         g_free (node->data);
01403     g_list_free (choices);
01404 
01405     if (choice < 0)
01406         return SCM_BOOL_F;
01407 
01408     if (choice == 0)
01409         return SCM_BOOL_T;
01410 
01411     choice--;
01412     if (choice >= scm_ilength (export_types))
01413         return SCM_BOOL_F;
01414 
01415     return scm_list_ref (export_types, scm_int2num (choice));
01416 }
01417 
01418 static char *
01419 gnc_get_export_filename (SCM choice)
01420 {
01421     char * filepath;
01422     struct stat statbuf;
01423     char * title;
01424     const gchar * html_type = _("HTML");
01425     char * type;
01426     int rc;
01427     char * default_dir;
01428 
01429     if (choice == SCM_BOOL_T)
01430         type = g_strdup (html_type);
01431     else
01432     {
01433         char * str;
01434         scm_dynwind_begin (0);
01435         str = scm_to_locale_string(SCM_CAR (choice));
01436         type = g_strdup (str);
01437         scm_dynwind_free (str);
01438         scm_dynwind_end ();
01439     }
01440 
01441     /* %s is the type of what is about to be saved, e.g. "HTML". */
01442     title = g_strdup_printf (_("Save %s To File"), type);
01443     default_dir = gnc_get_default_directory(GCONF_DIR_REPORT);
01444 
01445     filepath = gnc_file_dialog (title, NULL, default_dir, GNC_FILE_DIALOG_EXPORT);
01446 
01447     /* Try to test for extension on file name, add if missing */
01448     if (g_strrstr(filepath, ".") == NULL)
01449         filepath = g_strconcat(filepath, ".", g_ascii_strdown(type, strlen(type)), NULL);
01450 
01451     g_free (type);
01452     g_free (title);
01453     g_free (default_dir);
01454 
01455     if (!filepath)
01456         return NULL;
01457 
01458     default_dir = g_path_get_dirname(filepath);
01459     gnc_set_default_directory (GCONF_DIR_REPORT, default_dir);
01460     g_free(default_dir);
01461 
01462     rc = g_stat (filepath, &statbuf);
01463 
01464     /* Check for an error that isn't a non-existent file. */
01465     if (rc != 0 && errno != ENOENT)
01466     {
01467         /* %s is the strerror(3) string of the error that occurred. */
01468         const char *format = _("You cannot save to that filename.\n\n%s");
01469 
01470         gnc_error_dialog (NULL, format, strerror(errno));
01471         g_free(filepath);
01472         return NULL;
01473     }
01474 
01475     /* Check for a file that isn't a regular file. */
01476     if (rc == 0 && !S_ISREG (statbuf.st_mode))
01477     {
01478         const char *message = _("You cannot save to that file.");
01479 
01480         gnc_error_dialog (NULL, "%s", message);
01481         g_free(filepath);
01482         return NULL;
01483     }
01484 
01485     if (rc == 0)
01486     {
01487         const char *format = _("The file %s already exists. "
01488                                "Are you sure you want to overwrite it?");
01489 
01490         if (!gnc_verify_dialog (NULL, FALSE, format, filepath))
01491         {
01492             g_free(filepath);
01493             return NULL;
01494         }
01495     }
01496 
01497     return filepath;
01498 }
01499 
01500 static void
01501 gnc_plugin_page_report_save_cb( GtkAction *action, GncPluginPageReport *report )
01502 {
01503     GncPluginPageReportPrivate *priv;
01504     SCM save_func;
01505 
01506     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
01507     if (priv->cur_report == SCM_BOOL_F)
01508         return;
01509 
01510     save_func = scm_c_eval_string("gnc:report-save-to-savefile");
01511     scm_call_1(save_func, priv->cur_report);
01512 
01513     {
01514         GtkActionGroup *action_group =
01515             gnc_plugin_page_get_action_group(GNC_PLUGIN_PAGE(report));
01516         GtkAction *action =
01517             gtk_action_group_get_action (action_group, "ReportSaveAction");
01518         gtk_action_set_sensitive(action, FALSE);
01519     }
01520 }
01521 
01522 static void
01523 gnc_plugin_page_report_export_cb( GtkAction *action, GncPluginPageReport *report )
01524 {
01525     GncPluginPageReportPrivate *priv;
01526     char * filepath;
01527     SCM export_types;
01528     SCM export_thunk;
01529     gboolean result;
01530     SCM choice;
01531 
01532     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
01533     export_types = scm_call_1 (scm_c_eval_string ("gnc:report-export-types"),
01534                                priv->cur_report);
01535 
01536     export_thunk = scm_call_1 (scm_c_eval_string ("gnc:report-export-thunk"),
01537                                priv->cur_report);
01538 
01539     if (scm_is_list (export_types) && scm_is_procedure (export_thunk))
01540         choice = gnc_get_export_type_choice (export_types);
01541     else
01542         choice = SCM_BOOL_T;
01543 
01544     if (choice == SCM_BOOL_F)
01545         return;
01546 
01547     filepath = gnc_get_export_filename (choice);
01548     if (!filepath)
01549         return;
01550 
01551     if (scm_is_pair (choice))
01552     {
01553         SCM file_scm;
01554         SCM res;
01555 
01556         choice = SCM_CDR (choice);
01557         file_scm = scm_makfrom0str (filepath);
01558 
01559         res = scm_call_3 (export_thunk, priv->cur_report, choice, file_scm);
01560 
01561         result = (res != SCM_BOOL_F);
01562     }
01563     else
01564         result = gnc_html_export_to_file (priv->html, filepath);
01565 
01566     if (!result)
01567     {
01568         const char *fmt = _("Could not open the file %s. "
01569                             "The error is: %s");
01570         gnc_error_dialog( NULL, fmt, filepath ? filepath : "(null)",
01571                           strerror (errno) ? strerror (errno) : "" );
01572     }
01573 
01574     g_free(filepath);
01575     return;
01576 }
01577 
01578 static void
01579 error_handler(const char *str)
01580 {
01581     PWARN("Report Error: %s", str);
01582 }
01583 
01584 static void
01585 gnc_plugin_page_report_options_cb( GtkAction *action, GncPluginPageReport *report )
01586 {
01587     GncPluginPageReportPrivate *priv;
01588     SCM start_editor = scm_c_eval_string("gnc:report-edit-options");
01589     SCM result;
01590 
01591     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
01592     if (priv->cur_report == SCM_BOOL_F)
01593         return;
01594 
01595     result = gfec_apply(start_editor, scm_cons(priv->cur_report, SCM_EOL),
01596                         error_handler);
01597     if (result == SCM_BOOL_F || result == SCM_UNDEFINED)
01598     {
01599         gnc_warning_dialog(GTK_WIDGET(gnc_ui_get_toplevel()), "%s",
01600                            _("There are no options for this report."));
01601     }
01602     else
01603     {
01604         gnc_plugin_page_report_add_edited_report(priv, priv->cur_report);
01605     }
01606 }
01607 
01608 static GncInvoice *lookup_invoice(GncPluginPageReportPrivate *priv)
01609 {
01610     g_assert(priv);
01611     return gnc_option_db_lookup_invoice_option(priv->cur_odb, "General",
01612             "Invoice Number", NULL);
01613 }
01614 
01615 #define GCONF_GENERAL_REPORT_PDFEXPORT GCONF_GENERAL_REPORT "/pdf_export"
01616 
01617 static gchar *report_create_jobname(GncPluginPageReportPrivate *priv)
01618 {
01619     gchar *job_name = NULL;
01620     gchar *report_name = NULL;
01621     const gchar *report_number = "";
01622     gchar *job_date;
01623     const gchar *default_jobname = N_("GnuCash-Report");
01624 
01625     g_assert(priv);
01626 
01627     {
01628         // Look up the date format that was chosen in the gconf registry
01629         QofDateFormat date_format_here;
01630         QofDateFormat date_format_old = qof_date_format_get();
01631         char *format_code = gnc_gconf_get_string(GCONF_GENERAL_REPORT_PDFEXPORT,
01632                             "filename_date_format", NULL);
01633 
01634         if (format_code == NULL)
01635         {
01636             format_code = g_strdup("locale");
01637             g_warning("No gconf key found for " GCONF_GENERAL_REPORT_PDFEXPORT
01638                       "/filename_date_format, using default %s", format_code);
01639         }
01640         if (*format_code == '\0')
01641         {
01642             g_free(format_code);
01643             format_code = g_strdup("locale");
01644         }
01645 
01646         if (gnc_date_string_to_dateformat(format_code, &date_format_here))
01647         {
01648             PERR("Incorrect date format code");
01649             if (format_code != NULL)
01650                 free(format_code);
01651         }
01652 
01653         // To apply this chosen date format, temporarily switch the
01654         // process-wide default to our chosen date format. Note: It is a
01655         // totally brain-dead implementation of qof_print_date() to not offer a
01656         // variation where the QofDateFormat can be passed as an argument.
01657         // Hrmpf.
01658         qof_date_format_set(date_format_here);
01659 
01660         job_date = qof_print_date( time( NULL ) );
01661 
01662         // Restore to the original general  date format
01663         qof_date_format_set(date_format_old);
01664     }
01665 
01666 
01667     if (priv->cur_report == SCM_BOOL_F)
01668         report_name = g_strdup (_(default_jobname));
01669     else
01670     {
01671         /* Gather some information from the report to generate a
01672          * decent print job name.
01673          * FIXME: this is a bit of a hack. It would be better if each
01674          *        report had a hidden job name option, because the
01675          *        generic reporting code shouldn't know what makes
01676          *        a decent job name for each report.
01677          *
01678          *        Also, the "Report name" for an invoice report is
01679          *        "Printable Invoice", which is not what the user wants to see,
01680          *        so I added yet another hack below for this. cstim.
01681          */
01682         GncInvoice *invoice;
01683         report_name = gnc_option_db_lookup_string_option(priv->cur_odb, "General",
01684                       "Report name", NULL);
01685         if (!report_name)
01686             report_name = g_strdup (_(default_jobname));
01687         if (g_strcmp0(report_name, _("Printable Invoice")) == 0
01688                 || g_strcmp0(report_name, _("Tax Invoice")) == 0
01689                 || g_strcmp0(report_name, _("Easy Invoice")) == 0
01690                 || g_strcmp0(report_name, _("Fancy Invoice")) == 0)
01691         {
01692             /* Again HACK alert: We modify this single known string here into
01693              * something more appropriate. */
01694             g_free(report_name);
01695             report_name = g_strdup(_("Invoice"));
01696         }
01697 
01698         invoice = lookup_invoice(priv);
01699         if (invoice)
01700         {
01701             // Report is for an invoice. Hence, we get a number of the invoice.
01702             report_number = gncInvoiceGetID(invoice);
01703         }
01704     }
01705 
01706     if (report_name && job_date)
01707     {
01708         // Look up the sprintf format of the output name from the gconf registry
01709         char* format = gnc_gconf_get_string(GCONF_GENERAL_REPORT_PDFEXPORT, "filename_format", NULL);
01710         if (!format)
01711         {
01712             // Fallback name format in case the gconf does not contain this key
01713             format = g_strdup("%s_%s_%s");
01714             g_warning("No gconf key found for " GCONF_GENERAL_REPORT_PDFEXPORT "/filename_format, using default %s", format);
01715         }
01716 
01717         job_name = g_strdup_printf(format, report_name, report_number, job_date);
01718 
01719         g_free(format);
01720     }
01721     g_free (report_name);
01722     g_free (job_date);
01723 
01724     {
01725         char forbidden_char = '/';
01726         // Now remove the characters that are not allowed in file
01727         // names. FIXME: Check for all disallowed characters here!
01728         while (strchr(job_name, forbidden_char))
01729         {
01730             *strchr(job_name, forbidden_char) = '_';
01731         }
01732     }
01733 
01734     {
01735         /* And one final checking issue: We want to avoid allocating
01736          * the same name twice for a saved PDF.  Hence, we keep a
01737          * GHashTable with the usage count of existing output
01738          * names. (Because I'm lazy, I just use a static GHashTable
01739          * for this.) */
01740         gpointer value;
01741         gboolean already_found;
01742         g_assert(static_report_printnames);
01743 
01744         // Lookup the existing usage count
01745         value = g_hash_table_lookup(static_report_printnames, job_name);
01746         already_found = (value != NULL);
01747         if (!value)
01748         {
01749             value = GINT_TO_POINTER(0);
01750         }
01751 
01752         // Increment the stored usage count
01753         value = GINT_TO_POINTER(1 + GPOINTER_TO_INT(value));
01754         // and store it again
01755         g_hash_table_insert(static_report_printnames, g_strdup(job_name), value);
01756 
01757         // If the previous usage count was more than 0, append the current
01758         // count (which is now 2 or higher) to the resulting name
01759         if (already_found)
01760         {
01761             // The name was already in use, so modify the name again
01762             gchar *tmp = g_strdup_printf("%s_%d", job_name, (int) GPOINTER_TO_INT(value));
01763             g_free(job_name);
01764             job_name = tmp;
01765         }
01766     }
01767 
01768     return job_name;
01769 }
01770 
01771 static void
01772 gnc_plugin_page_report_print_cb( GtkAction *action, GncPluginPageReport *report )
01773 {
01774     GncPluginPageReportPrivate *priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
01775     gchar *job_name = report_create_jobname(priv);
01776 
01777     //g_warning("Setting job name=%s", job_name);
01778 
01779     gnc_html_print(priv->html, job_name, FALSE);
01780 
01781     g_free (job_name);
01782 }
01783 
01784 #define KVP_OWNER_EXPORT_PDF_DIRNAME "export-pdf-directory"
01785 
01786 static void
01787 gnc_plugin_page_report_exportpdf_cb( GtkAction *action, GncPluginPageReport *report )
01788 {
01789     GncPluginPageReportPrivate *priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
01790     gchar *job_name = report_create_jobname(priv);
01791     GncInvoice *invoice;
01792     GncOwner *owner = NULL;
01793     KvpFrame *kvp = NULL;
01794 
01795     // Do we have an invoice report?
01796     invoice = lookup_invoice(priv);
01797     if (invoice)
01798     {
01799         // Does this invoice also have an owner?
01800         owner = (GncOwner*) gncInvoiceGetOwner(invoice);
01801         if (owner)
01802         {
01803             // Yes. In the kvp, look up the key for the Export-PDF output
01804             // directory. If it exists, prepend this to the job name so that
01805             // we can export to PDF.
01806             kvp = gncOwnerGetSlots(owner);
01807             if (kvp)
01808             {
01809                 const char *dirname = kvp_frame_get_string(kvp, KVP_OWNER_EXPORT_PDF_DIRNAME);
01810                 if (dirname && g_file_test(dirname, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
01811                 {
01812                     gchar *tmp = g_build_filename(dirname, job_name, NULL);
01813                     g_free(job_name);
01814                     job_name = tmp;
01815                 }
01816             }
01817         }
01818     }
01819 
01820     //g_warning("Setting job name=%s", job_name);
01821 
01822     gnc_html_print(priv->html, job_name, TRUE);
01823 
01824     if (owner && kvp)
01825     {
01826         // As this is an invoice report with some owner, we will try to look up the
01827         // chosen output directory from the print settings and store it again in the owner kvp.
01828         GtkPrintSettings *print_settings = gnc_print_get_settings();
01829         if (print_settings && gtk_print_settings_has_key(print_settings, GNC_GTK_PRINT_SETTINGS_EXPORT_DIR))
01830         {
01831             const char* dirname = gtk_print_settings_get(print_settings,
01832                                   GNC_GTK_PRINT_SETTINGS_EXPORT_DIR);
01833             // Only store the directory if it exists.
01834             if (g_file_test(dirname, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
01835             {
01836                 QofInstance *qofinstance = qofOwnerGetOwner(owner);
01837                 //gncOwnerBeginEdit(owner);
01838                 kvp_frame_set_string(kvp, KVP_OWNER_EXPORT_PDF_DIRNAME, dirname);
01839                 if (qofinstance)
01840                     qof_instance_set_dirty(qofinstance);
01841                 // shoot... there is no such thing as: gncOwnerCommitEdit(owner);
01842             }
01843         }
01844     }
01845 
01846     g_free (job_name);
01847 }
01848 
01849 static void
01850 gnc_plugin_page_report_copy_cb(GtkAction *action, GncPluginPageReport *report)
01851 {
01852     GncPluginPageReportPrivate *priv;
01853 
01854     priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
01855     gnc_html_copy_to_clipboard(priv->html);
01856 }
01857 
01858 /********************************************************************
01859  * gnc_main_window_open_report()
01860  * open an report in a top level window from an ID number
01861  ********************************************************************/
01862 
01863 void
01864 gnc_main_window_open_report(int report_id, GncMainWindow *window)
01865 {
01866     GncPluginPage *reportPage;
01867 
01868     if (window)
01869         g_return_if_fail(GNC_IS_MAIN_WINDOW(window));
01870 
01871     reportPage = gnc_plugin_page_report_new( report_id );
01872     gnc_main_window_open_page( window, reportPage );
01873 }
01874 
01875 void
01876 gnc_main_window_open_report_url(const char * url, GncMainWindow *window)
01877 {
01878     GncPluginPage *reportPage;
01879 
01880     DEBUG( "report url: [%s]\n", url );
01881 
01882     if (window)
01883         g_return_if_fail(GNC_IS_MAIN_WINDOW(window));
01884 
01885     reportPage = gnc_plugin_page_report_new( 42 /* url? */ );
01886     gnc_main_window_open_page( window, reportPage );
01887 }
01888 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines