GnuCash  4.12-68-g5dc52459a1+
gnc-plugin-page-report.c
Go to the documentation of this file.
1 /* gnc-plugin-page-report.c
2  * Copyright (C) 2004 Joshua Sled <jsled@asynchronous.org>
3  * Copyright (C) 2005 David Hampton <hampton@employees.org>
4  *
5  * Originally from window-report.c:
6  * Copyright (C) 1997 Robin D. Clark
7  * Copyright (C) 1998 Linas Vepstas
8  * Copyright (C) 1999 Jeremy Collins ( gtk-xmhtml port )
9  * Copyright (C) 2000 Dave Peticolas
10  * Copyright (C) 2000 Bill Gribble
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License as
14  * published by the Free Software Foundation; either version 2 of
15  * the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, contact:
24  *
25  * Free Software Foundation Voice: +1-617-542-5942
26  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
27  * Boston, MA 02110-1301, USA gnu@gnu.org
28  */
29 
40 #include <config.h>
41 
42 #include <gtk/gtk.h>
43 #include <glib/gi18n.h>
44 #include <glib/gstdio.h>
45 #include <libguile.h>
46 #include <sys/stat.h>
47 #include <errno.h>
48 
49 #include <gnc-glib-utils.h>
50 #include "gfec.h"
51 #include "dialog-custom-report.h"
52 #include "dialog-utils.h"
53 #include "gnc-component-manager.h"
54 #include "gnc-engine.h"
55 #include "gnc-gnome-utils.h"
56 #include "gnc-guile-utils.h"
57 #include "gnc-html-history.h"
58 #include "gnc-html.h"
59 #include "gnc-html-factory.h"
60 #include "gnc-file.h"
61 #include "gnc-filepath-utils.h"
62 #include "gnc-plugin.h"
63 #include "gnc-plugin-page-report.h"
65 #include "gnc-prefs.h"
66 #include "gnc-report.h"
67 #include "gnc-session.h"
68 #include "gnc-ui-util.h"
69 #include "gnc-ui.h"
70 #include "gnc-window.h"
71 #include "option-util.h"
72 #include "window-report.h"
73 #include "swig-runtime.h"
74 #include "guile-mappings.h"
75 #include "business-options.h"
76 #include "gnc-icons.h"
77 #include "print-session.h"
78 
79 /* NW: you can add GNC_MOD_REPORT to gnc-engine.h
80 or simply define it locally. Any unique string with
81 a gnucash- prefix will do. Then just set a log level
82 with qof_log_set_level().*/
83 static QofLogModule log_module = GNC_MOD_GUI;
84 
85 static GObjectClass *parent_class = NULL;
86 
87 // A static GHashTable to record the usage count for each printer
88 // output name. FIXME: Currently this isn't cleaned up at program
89 // shutdown because there isn't a place to easily insert a finalize()
90 // function for this. Oh well.
91 static GHashTable *static_report_printnames = NULL;
92 
93 // Property-id values.
94 enum
95 {
96  PROP_0,
97  PROP_REPORT_ID,
98 };
99 
101 {
103  int reportId;
104  gint component_manager_id;
105 
109  GNCOptionDB *cur_odb;
110  SCM option_change_cb_id;
111 
112  /* initial_report is special; it's the one that's saved and
113  * restored. The name_change_callback only gets called when
114  * the initial_report name is changed. */
115  SCM initial_report;
116  GNCOptionDB * initial_odb;
117  SCM name_change_cb_id;
118 
119  /* keep a list of edited reports so that we can destroy them when
120  * the window is closed. */
121  SCM edited_reports;
122 
123  /* The page is in the process of reloading the html */
124  gboolean reloading;
125  gboolean loaded;
126 
128 // gnc_html *html;
129  GncHtml *html;
130 
132  GtkContainer *container;
134 
135 G_DEFINE_TYPE_WITH_PRIVATE(GncPluginPageReport, gnc_plugin_page_report, GNC_TYPE_PLUGIN_PAGE)
136 
137 #define GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(o) \
138  ((GncPluginPageReportPrivate*)gnc_plugin_page_report_get_instance_private((GncPluginPageReport*)o))
139 
140 static void gnc_plugin_page_report_class_init( GncPluginPageReportClass *klass );
141 static void gnc_plugin_page_report_init( GncPluginPageReport *plugin_page );
142 static GObject *gnc_plugin_page_report_constructor(GType this_type, guint n_properties, GObjectConstructParam *properties);
143 static void gnc_plugin_page_report_finalize (GObject *object);
144 static void gnc_plugin_page_report_setup( GncPluginPage *ppage );
145 
146 static void gnc_plugin_page_report_constr_init(GncPluginPageReport *plugin_page, gint reportId);
147 
148 static GtkWidget* gnc_plugin_page_report_create_widget( GncPluginPage *plugin_page );
149 static void gnc_plugin_page_report_destroy_widget( GncPluginPage *plugin_page );
150 static void gnc_plugin_page_report_save_page (GncPluginPage *plugin_page, GKeyFile *file, const gchar *group);
151 static GncPluginPage *gnc_plugin_page_report_recreate_page (GtkWidget *window, GKeyFile *file, const gchar *group);
152 static void gnc_plugin_page_report_name_changed (GncPluginPage *page, const gchar *name);
153 static void gnc_plugin_page_report_update_edit_menu (GncPluginPage *page, gboolean hide);
154 static gboolean gnc_plugin_page_report_finish_pending (GncPluginPage *page);
155 static void gnc_plugin_page_report_load_uri (GncPluginPage *page);
156 
157 static int gnc_plugin_page_report_check_urltype(URLType t);
158 //static void gnc_plugin_page_report_load_cb(gnc_html * html, URLType type,
159 static void gnc_plugin_page_report_load_cb(GncHtml * html, URLType type,
160  const gchar * location, const gchar * label,
161  gpointer data);
162 static void gnc_plugin_page_report_refresh (gpointer data);
163 static void gnc_plugin_page_report_set_fwd_button(GncPluginPageReport * page, int enabled);
164 static void gnc_plugin_page_report_set_back_button(GncPluginPageReport * page, int enabled);
165 static void gnc_plugin_page_report_history_destroy_cb(gnc_html_history_node * node, gpointer user_data);
166 static void close_handler(gpointer user_data);
167 void gnc_plugin_page_report_destroy(GncPluginPageReportPrivate *priv);
168 static void gnc_plugin_page_report_option_change_cb(gpointer data);
169 
170 void gnc_plugin_page_report_remove_edited_report(GncPluginPageReportPrivate *priv, SCM report);
171 void gnc_plugin_page_report_add_edited_report(GncPluginPageReportPrivate *priv, SCM report);
172 void gnc_plugin_page_report_raise_editor(SCM report);
173 
174 static void gnc_plugin_page_report_forw_cb(GtkAction *action, GncPluginPageReport *rep);
175 static void gnc_plugin_page_report_back_cb(GtkAction *action, GncPluginPageReport *rep);
176 static void gnc_plugin_page_report_reload_cb(GtkAction *action, GncPluginPageReport *rep);
177 static void gnc_plugin_page_report_stop_cb(GtkAction *action, GncPluginPageReport *rep);
178 static void gnc_plugin_page_report_save_cb(GtkAction *action, GncPluginPageReport *rep);
179 static void gnc_plugin_page_report_save_as_cb(GtkAction *action, GncPluginPageReport *rep);
180 static void gnc_plugin_page_report_export_cb(GtkAction *action, GncPluginPageReport *rep);
181 static void gnc_plugin_page_report_options_cb(GtkAction *action, GncPluginPageReport *rep);
182 static void gnc_plugin_page_report_print_cb(GtkAction *action, GncPluginPageReport *rep);
183 static void gnc_plugin_page_report_exportpdf_cb(GtkAction *action, GncPluginPageReport *rep);
184 static void gnc_plugin_page_report_copy_cb(GtkAction *action, GncPluginPageReport *rep);
185 
186 static void
187 gnc_plugin_page_report_get_property( GObject *obj,
188  guint prop_id,
189  GValue *value,
190  GParamSpec *pspec )
191 {
192  GncPluginPageReport *rep;
194 
195  rep = GNC_PLUGIN_PAGE_REPORT( obj );
196  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(rep);
197 
198  switch ( prop_id )
199  {
200  case PROP_REPORT_ID:
201  g_value_set_int( value, priv->reportId );
202  break;
203  default:
204  PERR( "Unknown property id %d", prop_id );
205  break;
206  }
207 }
208 
209 static void
210 gnc_plugin_page_report_set_property( GObject *obj,
211  guint prop_id,
212  const GValue *value,
213  GParamSpec *pspec )
214 {
215  GncPluginPageReport *rep;
217 
218  rep = GNC_PLUGIN_PAGE_REPORT( obj );
219  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(rep);
220 
221  DEBUG( "setting property with id %d / %p to value %d",
222  prop_id, priv, g_value_get_int( value ) );
223 
224  switch ( prop_id )
225  {
226  case PROP_REPORT_ID:
227  priv->reportId = g_value_get_int( value );
228  break;
229  default:
230  PERR( "unknown property id %d", prop_id );
231  break;
232  }
233 
234 }
235 
240 static gboolean
241 gnc_plugin_page_report_focus_widget (GncPluginPage *report_plugin_page)
242 {
243  if (GNC_IS_PLUGIN_PAGE_REPORT(report_plugin_page))
244  {
245  GncPluginPageReportPrivate *priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report_plugin_page);
246  GtkWidget *window;
247 
248  if (!priv)
249  return FALSE;
250 
251  window = gnc_plugin_page_get_window (report_plugin_page);
252 
253  if (window && !gnc_main_window_is_restoring_pages (GNC_MAIN_WINDOW(window)))
254  {
255  GtkWidget *widget = gnc_html_get_webview (priv->html);
256 
257  if (!priv->loaded) // so we only do the load once
258  gnc_plugin_page_report_load_uri (report_plugin_page);
259 
260  if (GTK_IS_WIDGET(widget))
261  {
262  if (!gtk_widget_is_focus (GTK_WIDGET(widget)))
263  gtk_widget_grab_focus (GTK_WIDGET(widget));
264  }
265  }
266  }
267  return FALSE;
268 }
269 
270 static void
271 gnc_plugin_page_report_class_init (GncPluginPageReportClass *klass)
272 {
273  GObjectClass *object_class = G_OBJECT_CLASS (klass);
274  GncPluginPageClass *gnc_plugin_page_class = GNC_PLUGIN_PAGE_CLASS(klass);
275 
276  parent_class = g_type_class_peek_parent (klass);
277 
278  object_class->constructor = gnc_plugin_page_report_constructor;
279  object_class->finalize = gnc_plugin_page_report_finalize;
280 
281  object_class->set_property = gnc_plugin_page_report_set_property;
282  object_class->get_property = gnc_plugin_page_report_get_property;
283 
284  gnc_plugin_page_class->tab_icon = GNC_ICON_ACCOUNT_REPORT;
285  gnc_plugin_page_class->plugin_name = GNC_PLUGIN_PAGE_REPORT_NAME;
286 
287  gnc_plugin_page_class->create_widget = gnc_plugin_page_report_create_widget;
288  gnc_plugin_page_class->destroy_widget = gnc_plugin_page_report_destroy_widget;
289  gnc_plugin_page_class->save_page = gnc_plugin_page_report_save_page;
290  gnc_plugin_page_class->recreate_page = gnc_plugin_page_report_recreate_page;
291  gnc_plugin_page_class->page_name_changed = gnc_plugin_page_report_name_changed;
292  gnc_plugin_page_class->update_edit_menu_actions = gnc_plugin_page_report_update_edit_menu;
293  gnc_plugin_page_class->finish_pending = gnc_plugin_page_report_finish_pending;
294  gnc_plugin_page_class->focus_page_function = gnc_plugin_page_report_focus_widget;
295 
296  // create the "reportId" property
297  g_object_class_install_property( object_class,
298  PROP_REPORT_ID,
299  g_param_spec_int( "report-id",
300  _("The numeric ID of the report."),
301  _("The numeric ID of the report."),
302  -1, G_MAXINT, -1, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE ) );
303 
304  /* JSLED: report-selected?
305  plugin_page_signals[ACCOUNT_SELECTED] =
306  g_signal_new ("account_selected",
307  G_OBJECT_CLASS_TYPE (object_class),
308  G_SIGNAL_RUN_FIRST,
309  G_STRUCT_OFFSET (GncPluginPageReportClass, account_selected),
310  NULL, NULL,
311  g_cclosure_marshal_VOID__POINTER,
312  G_TYPE_NONE, 1,
313  G_TYPE_POINTER);
314  */
315 
316  // Also initialize the report name usage count table
317  if (!static_report_printnames)
318  static_report_printnames = g_hash_table_new_full(g_str_hash,
319  g_str_equal, g_free, NULL);
320 }
321 
322 static void
323 gnc_plugin_page_report_finalize (GObject *object)
324 {
325  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REPORT (object));
326 
327  ENTER("object %p", object);
328  G_OBJECT_CLASS (parent_class)->finalize (object);
329  LEAVE(" ");
330 }
331 
332 static void
333 gnc_plugin_page_report_set_progressbar (GncPluginPage *page, gboolean set)
334 {
335  GtkWidget *progressbar;
336  GtkAllocation allocation;
337 
338  progressbar = gnc_window_get_progressbar (GNC_WINDOW(page->window));
339  gtk_widget_get_allocation (GTK_WIDGET(progressbar), &allocation);
340 
341  // this sets the minimum size of the progressbar to that allocated
342  if (set)
343  gtk_widget_set_size_request (GTK_WIDGET(progressbar), -1, allocation.height);
344  else
345  gtk_widget_set_size_request (GTK_WIDGET(progressbar), -1, -1); //reset
346 }
347 
348 static void
349 gnc_plugin_page_report_load_uri (GncPluginPage *page)
350 {
351  GncPluginPageReport *report;
353  URLType type;
354  char * id_name;
355  char * child_name;
356  char * url_location = NULL;
357  char * url_label = NULL;
358 
359  report = GNC_PLUGIN_PAGE_REPORT(page);
360  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
361  if (!priv)
362  return; // No priv means the page doesn't exist anymore.
363 
364  DEBUG( "Load uri id=%d", priv->reportId );
365  id_name = g_strdup_printf("id=%d", priv->reportId );
366  child_name = gnc_build_url( URL_TYPE_REPORT, id_name, NULL );
367  type = gnc_html_parse_url( priv->html, child_name, &url_location, &url_label);
368  DEBUG( "passing id_name=[%s] child_name=[%s] type=[%s], location=[%s], label=[%s]",
369  id_name, child_name ? child_name : "(null)",
370  type ? type : "(null)", url_location ? url_location : "(null)",
371  url_label ? url_label : "(null)" );
372 
373  g_free(id_name);
374  g_free(child_name);
375 
376  gtk_widget_show_all( GTK_WIDGET(priv->container) );
377 
378  priv->loaded = TRUE;
379 
380  // this sets the window for the progressbar
381  gnc_window_set_progressbar_window( GNC_WINDOW(page->window) );
382 
383  // this sets the minimum size of the progressbar to that allocated
384  gnc_plugin_page_report_set_progressbar( page, TRUE );
385 
386  gnc_html_show_url(priv->html, type, url_location, url_label, 0);
387  g_free(url_location);
388 
389  gnc_plugin_page_report_set_progressbar( page, FALSE );
390 
391  // this resets the window for the progressbar to NULL
392  gnc_window_set_progressbar_window( NULL );
393 }
394 
395 /* used to capture Ctrl+Alt+PgUp/Down for tab selection */
396 static gboolean
397 webkit_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
398 {
399  GncPluginPageReport *report = GNC_PLUGIN_PAGE_REPORT(user_data);
400  GncPluginPageReportPrivate *priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
401  GdkModifierType modifiers = gtk_accelerator_get_default_mod_mask ();
402  GtkWidget *window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(report));
403 
404  if (GNC_PLUGIN_PAGE(report) != gnc_main_window_get_current_page (GNC_MAIN_WINDOW(window)))
405  return FALSE;
406 
407  if ((event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_Page_Down ||
408  event->keyval == GDK_KEY_KP_Page_Up || event->keyval == GDK_KEY_KP_Page_Down)
409  && (event->state & modifiers) == (GDK_CONTROL_MASK | GDK_MOD1_MASK))
410  {
411  GtkNotebook *notebook = GTK_NOTEBOOK(gtk_widget_get_parent (GTK_WIDGET(priv->container)));
412  gint pages = gtk_notebook_get_n_pages (notebook);
413  gint current_page = gtk_notebook_get_current_page (notebook);
414 
415  if (event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_KP_Page_Up)
416  {
417  if (current_page == 0)
418  gtk_notebook_set_current_page (notebook, pages - 1);
419  else
420  gtk_notebook_prev_page (notebook);
421  }
422  else
423  {
424  if (pages == current_page + 1)
425  gtk_notebook_set_current_page (notebook, 0);
426  else
427  gtk_notebook_next_page (notebook);
428  }
429  return TRUE;
430  }
431  return FALSE;
432 }
433 
434 static
435 GtkWidget*
436 gnc_plugin_page_report_create_widget( GncPluginPage *page )
437 {
438  GncPluginPageReport *report;
440  GtkWindow *topLvl;
441  GtkAction *action;
442  GtkWidget *webview;
443  URLType type;
444  char * id_name;
445  char * child_name;
446  char * url_location = NULL;
447  char * url_label = NULL;
448 
449  ENTER("page %p", page);
450 
451 #ifndef WEBKIT1
452  /* Hide the ExportPdf action for Webkit2 */
453  action = gnc_plugin_page_get_action (page, "FilePrintPDFAction");
454  gtk_action_set_sensitive (action, FALSE);
455  gtk_action_set_visible (action, FALSE);
456 #endif
457 
458  report = GNC_PLUGIN_PAGE_REPORT(page);
459  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
460 
461  topLvl = gnc_ui_get_main_window (NULL);
462 // priv->html = gnc_html_new( topLvl );
463  priv->html = gnc_html_factory_create_html();
464  gnc_html_set_parent( priv->html, topLvl );
465  priv->loaded = FALSE;
466 
467  gnc_html_history_set_node_destroy_cb(gnc_html_get_history(priv->html),
468  gnc_plugin_page_report_history_destroy_cb,
469  (gpointer)priv);
470 
471  priv->container = GTK_CONTAINER(gtk_frame_new(NULL));
472  gtk_frame_set_shadow_type(GTK_FRAME(priv->container), GTK_SHADOW_NONE);
473 
474  // Set the name for this widget so it can be easily manipulated with css
475  gtk_widget_set_name (GTK_WIDGET(priv->container), "gnc-id-report-page");
476 
477  gtk_container_add(GTK_CONTAINER(priv->container),
478  gnc_html_get_widget(priv->html));
479 
480  priv->component_manager_id =
481  gnc_register_gui_component(WINDOW_REPORT_CM_CLASS, NULL,
482  close_handler, page);
483  gnc_gui_component_set_session(priv->component_manager_id,
484  gnc_get_current_session());
485 
486  gnc_html_set_urltype_cb(priv->html, gnc_plugin_page_report_check_urltype);
487  gnc_html_set_load_cb(priv->html, gnc_plugin_page_report_load_cb, report);
488 
489  /* We need to call the load call back so the report appears to have been run
490  so it will get saved properly if the report is not realized in session */
491  id_name = g_strdup_printf("id=%d", priv->reportId );
492  child_name = gnc_build_url( URL_TYPE_REPORT, id_name, NULL );
493  type = gnc_html_parse_url( priv->html, child_name, &url_location, &url_label);
494 
495  gnc_plugin_page_report_load_cb (priv->html, type, id_name, url_label, report);
496  g_free(id_name);
497  g_free(child_name);
498  g_free (url_label);
499  g_free (url_location);
500 
501  // FIXME. This is f^-1(f(x)), isn't it?
502  DEBUG( "id=%d", priv->reportId );
503 
504  g_signal_connect (G_OBJECT(page), "inserted",
505  G_CALLBACK(gnc_plugin_page_inserted_cb),
506  NULL);
507 
508  // used to capture Ctrl+Alt+PgUp/Down for tab selection
509  webview = gnc_html_get_webview (priv->html);
510  if (webview)
511  {
512  gtk_widget_add_events (webview, gtk_widget_get_events (webview) |
513  GDK_KEY_PRESS_MASK);
514 
515  g_signal_connect (webview, "key-press-event",
516  G_CALLBACK(webkit_key_press_event_cb),
517  page);
518  }
519 
520  gtk_widget_show_all( GTK_WIDGET(priv->container) );
521  LEAVE("container %p", priv->container);
522  return GTK_WIDGET( priv->container );
523 }
524 
525 /********************************************************************
526  * gnc_plugin_page_report_check_urltype
527  * is it OK to show a certain URLType in this window?
528  ********************************************************************/
529 static int
530 gnc_plugin_page_report_check_urltype(URLType t)
531 {
532  if (!g_strcmp0 (t, URL_TYPE_REPORT))
533  {
534  return TRUE;
535  }
536  else
537  {
538  return FALSE;
539  }
540 }
541 
546 static void
547 gnc_plugin_page_report_setup( GncPluginPage *ppage )
548 {
549  GncPluginPageReport *report = GNC_PLUGIN_PAGE_REPORT(ppage);
551  SCM set_needs_save = scm_c_eval_string("gnc:report-set-needs-save?!");
552  SCM inst_report;
553  int report_id;
554 
555  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
556  priv->cur_report = SCM_BOOL_F;
557  priv->initial_report = SCM_BOOL_F;
558  priv->edited_reports = SCM_EOL;
559  priv->name_change_cb_id = SCM_BOOL_F;
560 
561  g_object_get( ppage, "report-id", &report_id, NULL );
562 
563  PINFO("report-id: %d\n", report_id);
564 
565  /* get the inst-report from the Scheme-side hash, and get its
566  * options and editor thunk */
567  if ((inst_report = gnc_report_find(report_id)) == SCM_BOOL_F)
568  {
569  return;
570  }
571 
572  if (priv->initial_report == SCM_BOOL_F)
573  {
574  priv->initial_report = inst_report;
575  scm_gc_protect_object(priv->initial_report);
576  }
577 
578  // all reports need [to be] saved immediately after they're created.
579  PINFO("set needs save");
580  scm_call_2(set_needs_save, inst_report, SCM_BOOL_T);
581 }
582 
583 /********************************************************************
584  * gnc_plugin_page_report_load_cb
585  * called after a report is loaded into the gnc_html widget
586  ********************************************************************/
587 static void
588 //gnc_plugin_page_report_load_cb(gnc_html * html, URLType type,
589 gnc_plugin_page_report_load_cb(GncHtml * html, URLType type,
590  const gchar * location, const gchar * label,
591  gpointer data)
592 {
593  GncPluginPageReport *report = GNC_PLUGIN_PAGE_REPORT(data);
595  int report_id;
596  SCM get_options = scm_c_eval_string("gnc:report-options");
597  SCM set_needs_save = scm_c_eval_string("gnc:report-set-needs-save?!");
598  SCM inst_report;
599 
600  ENTER( "load_cb: type=[%s], location=[%s], label=[%s]",
601  type ? type : "(null)", location ? location : "(null)",
602  label ? label : "(null)" );
603 
604  /* we get this callback if a new report is requested to be loaded OR
605  * if any URL is clicked. If an options URL is clicked, we want to
606  * know about it */
607  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
608  if (!g_strcmp0 (type, URL_TYPE_REPORT)
609  && location
610  && (strlen(location) > 3)
611  && !strncmp("id=", location, 3))
612  {
613  report_id = atoi(location + 3);
614  DEBUG( "parsed id=%d", report_id );
615  }
616  else if (!g_strcmp0( type, URL_TYPE_OPTIONS)
617  && location
618  && (strlen(location) > 10)
619  && !strncmp("report-id=", location, 10))
620  {
621  report_id = atoi(location + 10);
622  inst_report = gnc_report_find(report_id);
623  if (inst_report != SCM_BOOL_F)
624  {
625  gnc_plugin_page_report_add_edited_report(priv, inst_report);
626  }
627  LEAVE("");
628  return;
629  }
630  else
631  {
632  LEAVE( " unknown URL type [%s] location [%s]", type, location );
633  return;
634  }
635 
636  /* get the inst-report from the hash, and get its
637  * options and editor thunk */
638  if ((inst_report = gnc_report_find(report_id)) == SCM_BOOL_F)
639  {
640  LEAVE( "error getting inst_report" );
641  return;
642  }
643 
644  if (priv->initial_report == SCM_BOOL_F)
645  {
646  priv->initial_report = inst_report;
647  scm_gc_protect_object(priv->initial_report);
648 
649  DEBUG("calling set_needs_save for report with id=%d", report_id);
650  scm_call_2(set_needs_save, inst_report, SCM_BOOL_T);
651 
652  priv->initial_odb = gnc_option_db_new(scm_call_1(get_options, inst_report));
653  priv->name_change_cb_id =
654  gnc_option_db_register_change_callback(priv->initial_odb,
655  gnc_plugin_page_report_refresh,
656  priv,
657  "General", "Report name");
658  }
659 
660  if ((priv->cur_report != SCM_BOOL_F) && (priv->cur_odb != NULL))
661  {
662  gnc_option_db_unregister_change_callback_id(priv->cur_odb,
663  priv->option_change_cb_id);
664  gnc_option_db_destroy(priv->cur_odb);
665  priv->cur_odb = NULL;
666  }
667 
668  if (priv->cur_report != SCM_BOOL_F)
669  scm_gc_unprotect_object(priv->cur_report);
670  priv->cur_report = inst_report;
671  scm_gc_protect_object(priv->cur_report);
672 
673  priv->cur_odb = gnc_option_db_new(scm_call_1(get_options, inst_report));
674  priv->option_change_cb_id =
675  gnc_option_db_register_change_callback(priv->cur_odb,
676  gnc_plugin_page_report_option_change_cb,
677  report, NULL, NULL);
678 
679  if (gnc_html_history_forward_p(gnc_html_get_history(priv->html)))
680  {
681  gnc_plugin_page_report_set_fwd_button(report, TRUE);
682  }
683  else
684  {
685  gnc_plugin_page_report_set_fwd_button(report, FALSE);
686  }
687 
688  if (gnc_html_history_back_p(gnc_html_get_history(priv->html)))
689  {
690  gnc_plugin_page_report_set_back_button(report, TRUE);
691  }
692  else
693  {
694  gnc_plugin_page_report_set_back_button(report, FALSE);
695  }
696 
697  LEAVE( "done" );
698 }
699 
700 
712 static void
713 gnc_plugin_page_report_option_change_cb(gpointer data)
714 {
715  GncPluginPage *page;
716  GncPluginPageReport *report;
718  SCM dirty_report = scm_c_eval_string("gnc:report-set-dirty?!");
719  const gchar *old_name;
720  gchar *new_name;
721 
722  g_return_if_fail(GNC_IS_PLUGIN_PAGE_REPORT(data));
723  report = GNC_PLUGIN_PAGE_REPORT(data);
724  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
725  page = GNC_PLUGIN_PAGE(report);
726 
727  DEBUG( "option_change" );
728  if (priv->cur_report == SCM_BOOL_F)
729  return;
730  DEBUG( "set-dirty, queue-draw" );
731 
732  /* Update the page (i.e. the notebook tab and window title) */
733  old_name = gnc_plugin_page_get_page_name(GNC_PLUGIN_PAGE(report));
734  new_name = gnc_option_db_lookup_string_option(priv->cur_odb, "General",
735  "Report name", NULL);
736  if (strcmp(old_name, new_name) != 0)
737  {
738  /* Bug 727130, 760711 - remove only the non-printable
739  * characters from the new name */
741  ENTER("Cleaned-up new report name: %s", new_name);
742  main_window_update_page_name(GNC_PLUGIN_PAGE(report), new_name);
743  }
744  g_free(new_name);
745 
746  /* it's probably already dirty, but make sure */
747  scm_call_2(dirty_report, priv->cur_report, SCM_BOOL_T);
748 
749  // prevent closing this page while loading...
750  priv->reloading = TRUE;
751 
752  // this sets the window for the progressbar
753  gnc_window_set_progressbar_window( GNC_WINDOW(page->window) );
754 
755  // this sets the minimum size of the progressbar to that allocated
756  gnc_plugin_page_report_set_progressbar( page, TRUE );
757 
758  /* Now queue the fact that we need to reload this report */
759  gnc_html_reload( priv->html, TRUE ); //reload by rebuild
760 
761  gnc_plugin_page_report_set_progressbar( page, FALSE );
762 
763  // this resets the window for the progressbar to NULL
764  gnc_window_set_progressbar_window( NULL );
765 
766  priv->reloading = FALSE;
767 }
768 
769 /* FIXME: This function does... nothing? */
770 static void
771 gnc_plugin_page_report_history_destroy_cb(gnc_html_history_node * node,
772  gpointer user_data)
773 {
774 #if 0
775  static SCM remover = SCM_BOOL_F;
776  int report_id;
777 
778  if (remover == SCM_BOOL_F)
779  {
780  remover = scm_c_eval_string("gnc:report-remove-by-id");
781  }
782 
783  if (node
784  && !g_strcmp0 (node->type, URL_TYPE_REPORT)\
785  && !strncmp("id=", node->location, 3))
786  {
787  sscanf(node->location + 3, "%d", &report_id);
788  /* printf("unreffing report %d and children\n", report_id);
789  scm_call_1(remover, scm_from_int (report_id)); */
790  }
791  else
792  {
793  return;
794  }
795 #endif
796 }
797 
798 // @param data is actually GncPluginPageReportPrivate
799 static void
800 gnc_plugin_page_report_refresh(gpointer data)
801 {
802  // FIXME?
803  DEBUG( "report-refresh called" );
804  // something like ... gnc_plugin_page_report_redraw( NULL, (GncPluginPageReportPrivate*)data );
805  return;
806 }
807 
808 static void
809 gnc_plugin_page_report_destroy_widget(GncPluginPage *plugin_page)
810 {
812 
813  // FIXME: cleanup other resources.
814 
815  PINFO("destroy widget");
816  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(plugin_page);
817 
818  // Remove the page_changed signal callback
819  gnc_plugin_page_disconnect_page_changed (GNC_PLUGIN_PAGE(plugin_page));
820 
821  // Remove the page focus idle function if present
822  g_idle_remove_by_data (plugin_page);
823 
824  if (priv->component_manager_id)
825  {
826  gnc_unregister_gui_component(priv->component_manager_id);
827  priv->component_manager_id = 0;
828  }
829 
830  gnc_plugin_page_report_destroy(priv);
831  gnc_report_remove_by_id(priv->reportId);
832 }
833 
834 
837 #define SCHEME_OPTIONS "SchemeOptions"
838 #define SCHEME_OPTIONS_N "SchemeOptions%d"
839 
840 
850 static void
851 gnc_plugin_page_report_save_page (GncPluginPage *plugin_page,
852  GKeyFile *key_file,
853  const gchar *group_name)
854 {
855  GncPluginPageReport *report;
857  SCM gen_save_text, scm_text;
858  SCM get_embedded_list, embedded, item, tmp_report;
859  SCM get_options;
860  gint count, id;
861  gchar *text, *key_name;
862 
863  g_return_if_fail (GNC_IS_PLUGIN_PAGE_REPORT(plugin_page));
864  g_return_if_fail (key_file != NULL);
865  g_return_if_fail (group_name != NULL);
866 
867  ENTER("page %p, key_file %p, group_name %s", plugin_page, key_file,
868  group_name);
869 
870  report = GNC_PLUGIN_PAGE_REPORT(plugin_page);
871  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
872 
873  if (!priv || !priv->cur_report || scm_is_null(priv->cur_report) ||
874  SCM_UNBNDP(priv->cur_report) || SCM_BOOL_F == priv->cur_report)
875  {
876  LEAVE("not saving invalid report");
877  return;
878  }
879 
880  gen_save_text = scm_c_eval_string("gnc:report-serialize");
881  get_embedded_list = scm_c_eval_string("gnc:report-embedded-list");
882  get_options = scm_c_eval_string("gnc:report-options");
883  embedded = scm_call_1(get_embedded_list, scm_call_1(get_options, priv->cur_report));
884  count = scm_ilength(embedded);
885  while (count-- > 0)
886  {
887  item = SCM_CAR(embedded);
888  embedded = SCM_CDR(embedded);
889  if (!scm_is_number(item))
890  continue;
891  id = scm_to_int (item);
892  tmp_report = gnc_report_find(id);
893  scm_text = scm_call_1(gen_save_text, tmp_report);
894  if (!scm_is_string (scm_text))
895  {
896  DEBUG("child report %d: nothing to save", id);
897  continue;
898  }
899 
900  key_name = g_strdup_printf(SCHEME_OPTIONS_N, id);
901  text = gnc_scm_strip_comments(scm_text);
902  g_key_file_set_value(key_file, group_name, key_name, text);
903  g_free(text);
904  g_free(key_name);
905  }
906 
907  scm_text = scm_call_1(gen_save_text, priv->cur_report);
908  if (!scm_is_string (scm_text))
909  {
910  LEAVE("nothing to save");
911  return;
912  }
913 
914  text = gnc_scm_strip_comments(scm_text);
915  g_key_file_set_value(key_file, group_name, SCHEME_OPTIONS, text);
916  g_free(text);
917  LEAVE(" ");
918 }
919 
920 
930 static GncPluginPage *
931 gnc_plugin_page_report_recreate_page (GtkWidget *window,
932  GKeyFile *key_file,
933  const gchar *group_name)
934 {
935  GncPluginPage *page;
936  gchar **keys;
937  gsize i, num_keys;
938  GError *error = NULL;
939  gchar *option_string;
940  gint report_id;
941  SCM scm_id, final_id = SCM_BOOL_F;
942  SCM report;
943 
944  g_return_val_if_fail(key_file, NULL);
945  g_return_val_if_fail(group_name, NULL);
946  ENTER("key_file %p, group_name %s", key_file, group_name);
947 
948  keys = g_key_file_get_keys(key_file, group_name, &num_keys, &error);
949  if (error)
950  {
951  g_warning("error reading group %s key list: %s",
952  group_name, error->message);
953  g_error_free(error);
954  LEAVE("no keys");
955  return NULL;
956  }
957 
958  for (i = 0; i < num_keys; i++)
959  {
960  if (strncmp(keys[i], SCHEME_OPTIONS, strlen(SCHEME_OPTIONS)) != 0)
961  continue;
962  option_string = g_key_file_get_value(key_file, group_name,
963  keys[i], &error);
964  if (error)
965  {
966  g_warning("error reading group %s key %s: %s",
967  group_name, keys[i], error->message);
968  g_error_free(error);
969  g_strfreev (keys);
970  LEAVE("bad value");
971  return NULL;
972  }
973  scm_id = scm_eval_string(scm_from_utf8_string(option_string));
974  g_free(option_string);
975 
976  if (!scm_integer_p(scm_id))
977  {
978  DEBUG("report id not an integer for key %s", keys[i]);
979  g_strfreev (keys);
980  return NULL;
981  }
982 
983  if (final_id == SCM_BOOL_F)
984  {
985  if (g_strcmp0(keys[i], SCHEME_OPTIONS) == 0)
986  {
987  final_id = scm_id;
988  }
989  }
990  }
991  g_strfreev (keys);
992 
993  if (final_id == SCM_BOOL_F)
994  {
995  LEAVE("report not specified");
996  return NULL;
997  }
998 
999  report_id = scm_to_int(final_id);
1000  report = gnc_report_find(report_id);
1001  if (!report)
1002  {
1003  LEAVE("report doesn't exist");
1004  return NULL;
1005  }
1006 
1007  page = gnc_plugin_page_report_new( report_id );
1008 
1009  LEAVE(" ");
1010  return page;
1011 }
1012 
1013 
1024 static void
1025 gnc_plugin_page_report_name_changed (GncPluginPage *page, const gchar *name)
1026 {
1028  const gchar *old_name;
1029 
1030  g_return_if_fail(GNC_IS_PLUGIN_PAGE_REPORT(page));
1031  g_return_if_fail(name != NULL);
1032 
1033  ENTER("page %p, name %s", page, name);
1034  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(page);
1035 
1036  /* Is this a redundant call? */
1037  old_name = gnc_option_db_lookup_string_option(priv->cur_odb, "General",
1038  "Report name", NULL);
1039  DEBUG("Comparing old name '%s' to new name '%s'",
1040  old_name ? old_name : "(null)", name);
1041  if (old_name && (strcmp(old_name, name) == 0))
1042  {
1043  LEAVE("no change");
1044  return;
1045  }
1046 
1047  /* Store the new name for the report. */
1048  gnc_option_db_set_string_option(priv->cur_odb, "General",
1049  "Report name", name);
1050 
1051  /* Have to manually call the option change hook. */
1052  gnc_plugin_page_report_option_change_cb(page);
1053  LEAVE(" ");
1054 }
1055 
1056 static void
1057 gnc_plugin_page_report_update_edit_menu (GncPluginPage *page, gboolean hide)
1058 {
1059  GtkAction *action;
1060 
1061  action = gnc_plugin_page_get_action (page, "EditCopyAction");
1062  gtk_action_set_sensitive (action, TRUE);
1063  gtk_action_set_visible (action, TRUE);
1064  action = gnc_plugin_page_get_action (page, "EditCutAction");
1065  gtk_action_set_sensitive (action, FALSE);
1066  gtk_action_set_visible (action, !hide);
1067  action = gnc_plugin_page_get_action (page, "EditPasteAction");
1068  gtk_action_set_sensitive (action, FALSE);
1069  gtk_action_set_visible (action, !hide);
1070 }
1071 
1072 static gboolean
1073 gnc_plugin_page_report_finish_pending (GncPluginPage *page)
1074 {
1076  GncPluginPageReport *report;
1077 
1078  report = GNC_PLUGIN_PAGE_REPORT(page);
1079  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1080  return !priv->reloading;
1081 }
1082 
1083 
1084 /********************************************************************
1085  * gnc_report_window_destroy
1086  * free and destroy a window
1087  ********************************************************************/
1088 void
1089 gnc_plugin_page_report_destroy(GncPluginPageReportPrivate * priv)
1090 {
1091  SCM get_editor = scm_c_eval_string("gnc:report-editor-widget");
1092  SCM set_editor = scm_c_eval_string("gnc:report-set-editor-widget!");
1093  SCM edited, editor;
1094 
1095  /* close any open editors */
1096  for (edited = scm_list_copy(priv->edited_reports); !scm_is_null(edited);
1097  edited = SCM_CDR(edited))
1098  {
1099  editor = scm_call_1(get_editor, SCM_CAR(edited));
1100  scm_call_2(set_editor, SCM_CAR(edited), SCM_BOOL_F);
1101  if (editor != SCM_BOOL_F)
1102  {
1103  GtkWidget *w = NULL;
1104 #define FUNC_NAME "gtk_widget_destroy"
1105  w = SWIG_MustGetPtr(editor,
1106  SWIG_TypeQuery("_p_GtkWidget"), 1, 0);
1107 #undef FUNC_NAME
1108  gtk_widget_destroy(GTK_WIDGET(w));
1109  }
1110  }
1111 
1112  if (priv->initial_odb)
1113  {
1114  gnc_option_db_unregister_change_callback_id(priv->initial_odb,
1115  priv->name_change_cb_id);
1116 
1117  gnc_option_db_destroy(priv->initial_odb);
1118  priv->initial_odb = NULL;
1119  }
1120 
1121  gnc_html_destroy(priv->html);
1122 
1123  priv->container = NULL;
1124  priv->html = NULL;
1125 
1126  if (priv->cur_report != SCM_BOOL_F)
1127  scm_gc_unprotect_object(priv->cur_report);
1128  if (priv->edited_reports != SCM_EOL)
1129  scm_gc_unprotect_object(priv->edited_reports);
1130 }
1131 
1133 static action_toolbar_labels toolbar_labels[] =
1134 {
1135  { "FilePrintAction", N_("Print") },
1136  { "ReportExportAction", N_("Export") },
1137  { "ReportOptionsAction", N_("Options") },
1138  /* Translators: This string is meant to be a short alternative for "Save Report Configuration"
1139  to be used as toolbar button label. */
1140  { "ReportSaveAction", N_("Save Config") },
1141  /* Translators: This string is meant to be a short alternative for "Save Report Configuration As..."
1142  to be used as toolbar button label. */
1143  { "ReportSaveAsAction", N_("Save Config As...") },
1144  { "FilePrintPDFAction", N_("Make Pdf") },
1145  { NULL, NULL },
1146 };
1147 
1148 static const gchar *initially_insensitive_actions[] =
1149 {
1150  NULL
1151 };
1152 
1153 static void
1154 gnc_plugin_page_report_init ( GncPluginPageReport *plugin_page )
1155 {
1156 }
1157 
1158 static GObject*
1159 gnc_plugin_page_report_constructor(GType this_type, guint n_properties, GObjectConstructParam *properties)
1160 {
1161  GObject *obj;
1162  GncPluginPageReportClass *our_class;
1163  GObjectClass *parent_class;
1164  gint reportId = -42;
1165  int i;
1166 
1167  our_class = GNC_PLUGIN_PAGE_REPORT_CLASS (
1168  g_type_class_peek (GNC_TYPE_PLUGIN_PAGE_REPORT));
1169  parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (our_class));
1170  obj = parent_class->constructor(this_type, n_properties, properties);
1171 
1172  for (i = 0; i < n_properties; i++)
1173  {
1174  GObjectConstructParam prop = properties[i];
1175  if (strcmp(prop.pspec->name, "report-id") == 0)
1176  {
1177  reportId = g_value_get_int(prop.value);
1178  }
1179  }
1180 
1181  gnc_plugin_page_report_constr_init(GNC_PLUGIN_PAGE_REPORT(obj), reportId);
1182 
1183  return obj;
1184 }
1185 
1186 static void
1187 gnc_plugin_page_report_constr_init(GncPluginPageReport *plugin_page, gint reportId)
1188 {
1190  GtkActionGroup *action_group;
1191  GncPluginPage *parent;
1192  gboolean use_new;
1193  gchar *name;
1194  gchar *saved_reports_path = gnc_build_userdata_path (SAVED_REPORTS_FILE);
1195  gchar *report_save_str = g_strdup_printf (
1196  _("Update the current report's saved configuration. "
1197  "The report configuration will be saved in the file %s."), saved_reports_path);
1198  gchar *report_saveas_str = g_strdup_printf (
1199  _("Add the current report's configuration to the 'Reports->Saved Report Configurations' menu. "
1200  "The report configuration will be saved in the file %s."), saved_reports_path);
1201 
1202  GtkActionEntry report_actions[] =
1203  {
1204  {
1205  "FilePrintAction", "document-print", N_("_Print Report..."), "<primary>p",
1206  N_("Print the current report"),
1207  G_CALLBACK(gnc_plugin_page_report_print_cb)
1208  },
1209  {
1210  "FilePrintPDFAction", GNC_ICON_PDF_EXPORT, N_("Export as P_DF..."), NULL,
1211  N_("Export the current report as a PDF document"),
1212  G_CALLBACK(gnc_plugin_page_report_exportpdf_cb)
1213  },
1214 
1215  {
1216  "EditCutAction", "edit-cut", N_("Cu_t"), "<primary>X",
1217  N_("Cut the current selection and copy it to clipboard"),
1218  NULL
1219  },
1220  {
1221  "EditCopyAction", "edit-copy", N_("_Copy"), "<primary>C",
1222  N_("Copy the current selection to clipboard"),
1223  G_CALLBACK(gnc_plugin_page_report_copy_cb)
1224  },
1225  {
1226  "EditPasteAction", "edit-paste", N_("_Paste"), "<primary>V",
1227  N_("Paste the clipboard content at the cursor position"),
1228  NULL
1229  },
1230  {
1231  "ViewRefreshAction", "view-refresh", N_("_Refresh"), "<primary>r",
1232  N_("Refresh this window"),
1233  G_CALLBACK (gnc_plugin_page_report_reload_cb)
1234  },
1235  {
1236  "ReportSaveAction", "document-save", N_("Save _Report Configuration"), "<primary><alt>s",
1237  report_save_str, G_CALLBACK(gnc_plugin_page_report_save_cb)
1238  },
1239  {
1240  "ReportSaveAsAction", "document-save-as", N_("Save Report Configuration As..."), "<primary><alt><shift>s",
1241  report_saveas_str, G_CALLBACK(gnc_plugin_page_report_save_as_cb)
1242  },
1243  {
1244  "ReportExportAction", "go-next", N_("Export _Report"), NULL,
1245  N_("Export HTML-formatted report to file"),
1246  G_CALLBACK(gnc_plugin_page_report_export_cb)
1247  },
1248  {
1249  "ReportOptionsAction", "document-properties", N_("_Report Options"), NULL,
1250  N_("Edit report options"),
1251  G_CALLBACK(gnc_plugin_page_report_options_cb)
1252  },
1253 
1254  {
1255  "ReportBackAction", "go-previous", N_("Back"), NULL,
1256  N_("Move back one step in the history"),
1257  G_CALLBACK(gnc_plugin_page_report_back_cb)
1258  },
1259  {
1260  "ReportForwAction", "go-next", N_("Forward"), NULL,
1261  N_("Move forward one step in the history"),
1262  G_CALLBACK(gnc_plugin_page_report_forw_cb)
1263  },
1264  {
1265  "ReportReloadAction", "view-refresh", N_("Reload"), NULL,
1266  N_("Reload the current page"),
1267  G_CALLBACK(gnc_plugin_page_report_reload_cb)
1268  },
1269  {
1270  "ReportStopAction", "process-stop", N_("Stop"), NULL,
1271  N_("Cancel outstanding HTML requests"),
1272  G_CALLBACK(gnc_plugin_page_report_stop_cb)
1273  },
1274  };
1275  guint num_report_actions = G_N_ELEMENTS( report_actions );
1276 
1277  DEBUG( "property reportId=%d", reportId );
1278  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(plugin_page);
1279  priv->reportId = reportId;
1280 
1281  gnc_plugin_page_report_setup( GNC_PLUGIN_PAGE(plugin_page) );
1282 
1283  /* Init parent declared variables */
1284  parent = GNC_PLUGIN_PAGE(plugin_page);
1285  use_new = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REPORT, GNC_PREF_USE_NEW);
1286  name = gnc_report_name( priv->initial_report );
1287  g_object_set(G_OBJECT(plugin_page),
1288  "page-name", name,
1289  "page-uri", "default:",
1290  "ui-description", "gnc-plugin-page-report-ui.xml",
1291  "use-new-window", use_new,
1292  NULL);
1293  g_free(name);
1294 
1295  /* change me when the system supports multiple books */
1296  gnc_plugin_page_add_book(parent, gnc_get_current_book());
1297 
1298  /* Create menu and toolbar information */
1299  action_group =
1301  "GncPluginPageReportActions");
1302  gtk_action_group_add_actions( action_group,
1303  report_actions,
1304  num_report_actions,
1305  plugin_page );
1306  gnc_plugin_update_actions(action_group,
1307  initially_insensitive_actions,
1308  "sensitive", FALSE);
1309  gnc_plugin_init_short_names (action_group, toolbar_labels);
1310 
1311  g_free (saved_reports_path);
1312  g_free (report_save_str);
1313  g_free (report_saveas_str);
1314 }
1315 
1318 {
1319  GncPluginPageReport *plugin_page;
1320 
1321  DEBUG( "report id = %d", reportId );
1322  plugin_page = g_object_new( GNC_TYPE_PLUGIN_PAGE_REPORT,
1323  "report-id", reportId, NULL );
1324  DEBUG( "plugin_page: %p", plugin_page );
1325  DEBUG( "set %d on page %p", reportId, plugin_page );
1326  return GNC_PLUGIN_PAGE( plugin_page );
1327 }
1328 
1329 void
1330 gnc_plugin_page_report_remove_edited_report(GncPluginPageReportPrivate *priv,
1331  SCM report)
1332 {
1333  SCM new_edited = scm_delete(priv->edited_reports, report);
1334  if (priv->edited_reports != SCM_EOL)
1335  scm_gc_unprotect_object(priv->edited_reports);
1336  priv->edited_reports = new_edited;
1337  if (new_edited != SCM_EOL)
1338  scm_gc_protect_object(priv->edited_reports);
1339 }
1340 
1341 void
1342 gnc_plugin_page_report_add_edited_report(GncPluginPageReportPrivate *priv,
1343  SCM report)
1344 {
1345  SCM new_edited = scm_cons(report, priv->edited_reports);
1346  if (priv->edited_reports != SCM_EOL)
1347  scm_gc_unprotect_object(priv->edited_reports);
1348  priv->edited_reports = new_edited;
1349  if (new_edited != SCM_EOL)
1350  scm_gc_protect_object(priv->edited_reports);
1351 }
1352 
1353 void
1354 gnc_plugin_page_report_raise_editor(SCM report)
1355 {
1356  SCM get_editor = scm_c_eval_string("gnc:report-editor-widget");
1357  SCM editor = scm_call_1(get_editor, report);
1358 #define FUNC_NAME "gtk_window_present"
1359  GtkWidget *w = SWIG_MustGetPtr(editor,
1360  SWIG_TypeQuery("_p_GtkWidget"), 1, 0);
1361 #undef FUNC_NAME
1362  gtk_window_present(GTK_WINDOW(w));
1363 }
1364 
1365 static void
1366 close_handler (gpointer user_data)
1367 {
1368  GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(user_data);
1369  DEBUG("in close handler\n");
1370  gnc_main_window_close_page (plugin_page);
1371 }
1372 
1373 static void
1374 gnc_plugin_page_report_set_fwd_button(GncPluginPageReport *report, int enabled)
1375 {
1376  GtkAction *act;
1377 
1378  act = gnc_plugin_page_get_action(GNC_PLUGIN_PAGE(report),
1379  "ReportForwAction" );
1380  gtk_action_set_sensitive(act, enabled);
1381 }
1382 
1383 static void
1384 gnc_plugin_page_report_set_back_button(GncPluginPageReport *report, int enabled)
1385 {
1386  GtkAction *act;
1387 
1388  act = gnc_plugin_page_get_action(GNC_PLUGIN_PAGE(report),
1389  "ReportBackAction" );
1390  gtk_action_set_sensitive(act, enabled);
1391 }
1392 
1393 // ------------------------------------------------------------
1394 // GTK ACTION CALLBACKS
1395 
1396 static void
1397 gnc_plugin_page_report_forw_cb( GtkAction *action, GncPluginPageReport *report )
1398 {
1400  gnc_html_history_node * node = NULL;
1401 
1402  DEBUG( "forw" );
1403  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1404  gnc_html_history_forward(gnc_html_get_history(priv->html));
1405  node = gnc_html_history_get_current(gnc_html_get_history(priv->html));
1406  if (node)
1407  {
1408  gnc_html_show_url(priv->html, node->type, node->location,
1409  node->label, 0);
1410  }
1411 }
1412 
1413 static void
1414 gnc_plugin_page_report_back_cb( GtkAction *action, GncPluginPageReport *report )
1415 {
1417  gnc_html_history_node * node;
1418 
1419  DEBUG( "back" );
1420  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1421  gnc_html_history_back(gnc_html_get_history(priv->html));
1422  node = gnc_html_history_get_current(gnc_html_get_history(priv->html));
1423  if (node)
1424  {
1425  gnc_html_show_url(priv->html, node->type, node->location,
1426  node->label, 0);
1427  }
1428 }
1429 
1430 void
1431 gnc_plugin_page_report_reload (GncPluginPageReport *report)
1432 {
1433  gnc_plugin_page_report_reload_cb (NULL, report);
1434 }
1435 
1436 static void
1437 gnc_plugin_page_report_reload_cb( GtkAction *action, GncPluginPageReport *report )
1438 {
1439  GncPluginPage *page;
1441  SCM dirty_report;
1442 
1443  DEBUG( "reload" );
1444  page = GNC_PLUGIN_PAGE(report);
1445  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1446  if (priv->cur_report == SCM_BOOL_F)
1447  return;
1448 
1449  DEBUG( "reload-redraw" );
1450  dirty_report = scm_c_eval_string("gnc:report-set-dirty?!");
1451  scm_call_2(dirty_report, priv->cur_report, SCM_BOOL_T);
1452 
1453  /* now queue the fact that we need to reload this report */
1454 
1455  // prevent closing this page while loading...
1456  priv->reloading = TRUE;
1457  // this sets the window for the progressbar
1458  gnc_window_set_progressbar_window( GNC_WINDOW(page->window) );
1459 
1460  // this sets the minimum size of the progressbar to that allocated
1461  gnc_plugin_page_report_set_progressbar( page, TRUE );
1462 
1463  gnc_html_reload( priv->html, TRUE ); //reload by rebuild
1464 
1465  gnc_plugin_page_report_set_progressbar( page, FALSE );
1466 
1467  // this resets the window for the progressbar to NULL
1468  gnc_window_set_progressbar_window( NULL );
1469  priv->reloading = FALSE;
1470 }
1471 
1472 static void
1473 gnc_plugin_page_report_stop_cb( GtkAction *action, GncPluginPageReport *report )
1474 {
1476 
1477  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1478  gnc_html_cancel(priv->html);
1479 }
1480 
1481 /* Returns SCM_BOOL_F if cancel. Returns SCM_BOOL_T if html.
1482  * Otherwise returns pair from export_types. */
1483 static SCM
1484 gnc_get_export_type_choice (SCM export_types, GtkWindow *parent)
1485 {
1486  GList * choices = NULL;
1487  gboolean bad = FALSE;
1488  GList * node;
1489  int choice;
1490  SCM tail;
1491 
1492  if (!scm_is_list (export_types))
1493  return SCM_BOOL_F;
1494 
1495  for (tail = export_types; !scm_is_null (tail); tail = SCM_CDR (tail))
1496  {
1497  SCM pair = SCM_CAR (tail);
1498  char * name;
1499  SCM scm;
1500 
1501  if (!scm_is_pair (pair))
1502  {
1503  g_warning ("unexpected list element");
1504  bad = TRUE;
1505  break;
1506  }
1507 
1508  scm = SCM_CAR (pair);
1509  if (!scm_is_string (scm))
1510  {
1511  g_warning ("unexpected pair element");
1512  bad = TRUE;
1513  break;
1514  }
1515 
1516  name = gnc_scm_to_utf8_string (scm);
1517  choices = g_list_prepend (choices, name);
1518  }
1519 
1520  if (!bad)
1521  {
1522  choices = g_list_reverse (choices);
1523 
1524  choices = g_list_prepend (choices, g_strdup (_("HTML")));
1525 
1526  choice = gnc_choose_radio_option_dialog
1527  (GTK_WIDGET (parent), _("Choose export format"),
1528  _("Choose the export format for this report:"),
1529  NULL, 0, choices);
1530  }
1531  else
1532  choice = -1;
1533 
1534  for (node = choices; node; node = node->next)
1535  g_free (node->data);
1536  g_list_free (choices);
1537 
1538  if (choice < 0)
1539  return SCM_BOOL_F;
1540 
1541  if (choice == 0)
1542  return SCM_BOOL_T;
1543 
1544  choice--;
1545  if (choice >= scm_ilength (export_types))
1546  return SCM_BOOL_F;
1547 
1548  return scm_list_ref (export_types, scm_from_int (choice));
1549 }
1550 
1551 static char *
1552 gnc_get_export_filename (SCM choice, GtkWindow *parent)
1553 {
1554  char * filepath;
1555  GStatBuf statbuf;
1556  char * title;
1557  const gchar * html_type = _("HTML");
1558  char * type;
1559  int rc;
1560  char * default_dir;
1561 
1562  if (choice == SCM_BOOL_T)
1563  type = g_strdup (html_type);
1564  else
1565  type = gnc_scm_to_utf8_string(SCM_CAR (choice));
1566 
1567  /* %s is the type of what is about to be saved, e.g. "HTML". */
1568  title = g_strdup_printf (_("Save %s To File"), type);
1569  default_dir = gnc_get_default_directory(GNC_PREFS_GROUP_REPORT);
1570 
1571  filepath = gnc_file_dialog (parent, title, NULL, default_dir,
1572  GNC_FILE_DIALOG_EXPORT);
1573 
1574  if (filepath != NULL) // test for cancel pressed
1575  {
1576  /* Try to test for extension on file name, add if missing */
1577  if (g_strrstr(filepath, ".") == NULL)
1578  filepath = g_strconcat(filepath, ".", g_ascii_strdown(type, strlen(type)), NULL);
1579  }
1580  g_free (type);
1581  g_free (title);
1582  g_free (default_dir);
1583 
1584  if (!filepath)
1585  return NULL;
1586 
1587  default_dir = g_path_get_dirname(filepath);
1588  gnc_set_default_directory (GNC_PREFS_GROUP_REPORT, default_dir);
1589  g_free(default_dir);
1590 
1591  rc = g_stat (filepath, &statbuf);
1592 
1593  /* Check for an error that isn't a non-existent file. */
1594  if (rc != 0 && errno != ENOENT)
1595  {
1596  /* %s is the strerror(3) string of the error that occurred. */
1597  const char *format = _("You cannot save to that filename.\n\n%s");
1598 
1599  gnc_error_dialog (parent, format, strerror(errno));
1600  g_free(filepath);
1601  return NULL;
1602  }
1603 
1604  /* Check for a file that isn't a regular file. */
1605  if (rc == 0 && !S_ISREG (statbuf.st_mode))
1606  {
1607  const char *message = _("You cannot save to that file.");
1608 
1609  gnc_error_dialog (parent, "%s", message);
1610  g_free(filepath);
1611  return NULL;
1612  }
1613 
1614  if (rc == 0)
1615  {
1616  const char *format = _("The file %s already exists. "
1617  "Are you sure you want to overwrite it?");
1618 
1619  if (!gnc_verify_dialog (parent, FALSE, format, filepath))
1620  {
1621  g_free(filepath);
1622  return NULL;
1623  }
1624  }
1625 
1626  return filepath;
1627 }
1628 
1629 static void
1630 gnc_plugin_page_report_save_as_cb( GtkAction *action, GncPluginPageReport *report )
1631 {
1633  SCM save_func;
1634  SCM rpt_id;
1635 
1636  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1637  if (priv->cur_report == SCM_BOOL_F)
1638  return;
1639 
1640  /* Create a new report template based on the current report's settings
1641  * and allow the user to rename the template.
1642  */
1643  save_func = scm_c_eval_string("gnc:report-to-template-new");
1644  rpt_id = scm_call_1(save_func, priv->cur_report);
1645 
1646  /* Open Preconfigured Reports dialog to allow user to change the name */
1647  if (!scm_is_null (rpt_id))
1648  {
1649  GncPluginPage *reportPage = GNC_PLUGIN_PAGE (report);
1650  GtkWidget *window = reportPage->window;
1651 
1652  if (window)
1653  g_return_if_fail(GNC_IS_MAIN_WINDOW(window));
1654 
1655  gnc_ui_custom_report_edit_name (GNC_MAIN_WINDOW (window), rpt_id);
1656  }
1657 
1658 }
1659 
1660 static void
1661 gnc_plugin_page_report_save_cb( GtkAction *action, GncPluginPageReport *report )
1662 {
1664  SCM check_func, save_func;
1665  SCM rpt_id;
1666 
1667  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1668  if (priv->cur_report == SCM_BOOL_F)
1669  return;
1670 
1671  check_func = scm_c_eval_string("gnc:is-custom-report-type");
1672  if (scm_is_true (scm_call_1 (check_func, priv->cur_report)))
1673  {
1674  /* The current report is already based on a custom report.
1675  * Replace the existing one instead of adding a new one
1676  */
1677  save_func = scm_c_eval_string("gnc:report-to-template-update");
1678  rpt_id = scm_call_1(save_func, priv->cur_report);
1679  (void)rpt_id;
1680  }
1681  else
1682  {
1683  /* The current report is not based on a custom report.
1684  * So let's create a new report template based on this report
1685  * and allow the user to change the name.
1686  */
1687  gnc_plugin_page_report_save_as_cb (action, report);
1688  }
1689 }
1690 
1691 static void
1692 gnc_plugin_page_report_export_cb( GtkAction *action, GncPluginPageReport *report )
1693 {
1695  char * filepath;
1696  SCM export_types;
1697  SCM export_thunk;
1698  gboolean result;
1699  SCM choice;
1700  GtkWindow *parent = GTK_WINDOW (gnc_plugin_page_get_window
1701  (GNC_PLUGIN_PAGE (report)));
1702 
1703  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1704  export_types = scm_call_1 (scm_c_eval_string ("gnc:report-export-types"),
1705  priv->cur_report);
1706 
1707  export_thunk = scm_call_1 (scm_c_eval_string ("gnc:report-export-thunk"),
1708  priv->cur_report);
1709 
1710  if (scm_is_list (export_types) && scm_is_procedure (export_thunk))
1711  choice = gnc_get_export_type_choice (export_types, parent);
1712  else
1713  choice = SCM_BOOL_T;
1714 
1715  if (choice == SCM_BOOL_F)
1716  return;
1717 
1718  filepath = gnc_get_export_filename (choice, parent);
1719  if (!filepath)
1720  return;
1721 
1722  if (scm_is_pair (choice))
1723  {
1724  SCM type = scm_cdr (choice);
1725  SCM document = scm_call_2 (export_thunk, priv->cur_report, type);
1726  SCM query_result = scm_c_eval_string ("gnc:html-document?");
1727  SCM get_export_string = scm_c_eval_string ("gnc:html-document-export-string");
1728  SCM get_export_error = scm_c_eval_string ("gnc:html-document-export-error");
1729 
1730  if (scm_is_false (scm_call_1 (query_result, document)))
1731  gnc_error_dialog (parent, _("This report must be upgraded to \
1732 return a document object with export-string or export-error."));
1733  else
1734  {
1735  SCM export_string = scm_call_1 (get_export_string, document);
1736  SCM export_error = scm_call_1 (get_export_error, document);
1737 
1738  if (scm_is_string (export_string))
1739  {
1740  GError *err = NULL;
1741  gchar *exported = scm_to_utf8_string (export_string);
1742  if (!g_file_set_contents (filepath, exported, -1, &err))
1743  gnc_error_dialog (parent, "Error during export: %s", err->message);
1744  g_free (exported);
1745  if (err)
1746  g_error_free (err);
1747  }
1748  else if (scm_is_string (export_error))
1749  {
1750  gchar *str = scm_to_utf8_string (export_error);
1751  gnc_error_dialog (parent, "error during export: %s", str);
1752  g_free (str);
1753  }
1754  else
1755  gnc_error_dialog (parent, _("This report must be upgraded to \
1756 return a document object with export-string or export-error."));
1757  }
1758  result = TRUE;
1759  }
1760  else
1761  result = gnc_html_export_to_file (priv->html, filepath);
1762 
1763  if (!result)
1764  {
1765  const char *fmt = _("Could not open the file %s. "
1766  "The error is: %s");
1767  gnc_error_dialog (parent, fmt, filepath ? filepath : "(null)",
1768  strerror (errno) ? strerror (errno) : "" );
1769  }
1770 
1771  g_free(filepath);
1772  return;
1773 }
1774 
1775 static void
1776 gnc_plugin_page_report_options_cb( GtkAction *action, GncPluginPageReport *report )
1777 {
1779  GtkWindow *parent = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (report)));
1780  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1781  if (priv->cur_report == SCM_BOOL_F)
1782  return;
1783 
1784  if (gnc_report_edit_options (priv->cur_report, parent))
1785  gnc_plugin_page_report_add_edited_report(priv, priv->cur_report);
1786 }
1787 
1788 static GncInvoice *lookup_invoice(GncPluginPageReportPrivate *priv)
1789 {
1790  g_assert(priv);
1791  return gnc_option_db_lookup_invoice_option(priv->cur_odb, "General",
1792  "Invoice Number", NULL);
1793 }
1794 
1795 #define GNC_PREFS_GROUP_REPORT_PDFEXPORT GNC_PREFS_GROUP_GENERAL_REPORT ".pdf-export"
1796 #define GNC_PREF_FILENAME_DATE_FMT "filename-date-format"
1797 #define GNC_PREF_FILENAME_FMT "filename-format"
1798 
1799 static gchar *report_create_jobname(GncPluginPageReportPrivate *priv)
1800 {
1801  gchar *job_name = NULL;
1802  gchar *report_name = NULL;
1803  const gchar *report_number = "";
1804  gchar *job_date;
1805  const gchar *default_jobname = N_("GnuCash-Report");
1806 
1807  g_assert(priv);
1808 
1809  {
1810  // Look up the date format that was chosen in the preferences database
1811  QofDateFormat date_format_here = QOF_DATE_FORMAT_ISO;
1812  char *format_code = gnc_prefs_get_string (GNC_PREFS_GROUP_REPORT_PDFEXPORT,
1813  GNC_PREF_FILENAME_DATE_FMT);
1814  const gchar *date_format_string;
1815  if (!(format_code && *format_code))
1816  {
1817  g_free(format_code);
1818  format_code = g_strdup("locale");
1819  }
1820 
1821  if (gnc_date_string_to_dateformat (format_code, &date_format_here))
1822  PERR("Incorrect date format code, using ISO-8601.");
1823 
1824  date_format_string = qof_date_format_get_string (date_format_here);
1825 
1826  job_date = gnc_print_time64 (gnc_time (NULL), date_format_string);
1827  g_free (format_code);
1828  }
1829 
1830 
1831  if (priv->cur_report == SCM_BOOL_F)
1832  report_name = g_strdup (_(default_jobname));
1833  else
1834  {
1835  /* Gather some information from the report to generate a
1836  * decent print job name.
1837  * FIXME: this is a bit of a hack. It would be better if each
1838  * report had a hidden job name option, because the
1839  * generic reporting code shouldn't know what makes
1840  * a decent job name for each report.
1841  *
1842  * Also, the "Report name" for an invoice report is
1843  * "Printable Invoice", which is not what the user wants to see,
1844  * so I added yet another hack below for this. cstim.
1845  */
1846  GncInvoice *invoice;
1847  report_name = gnc_option_db_lookup_string_option(priv->cur_odb, "General",
1848  "Report name", NULL);
1849  if (!report_name)
1850  report_name = g_strdup (_(default_jobname));
1851  if (g_strcmp0(report_name, _("Printable Invoice")) == 0
1852  || g_strcmp0(report_name, _("Tax Invoice")) == 0
1853  || g_strcmp0(report_name, _("Easy Invoice")) == 0
1854  || g_strcmp0(report_name, _("Fancy Invoice")) == 0)
1855  {
1856  /* Again HACK alert: We modify this single known string here into
1857  * something more appropriate. */
1858  g_free(report_name);
1859  report_name = g_strdup(_("Invoice"));
1860  }
1861 
1862  invoice = lookup_invoice(priv);
1863  if (invoice)
1864  {
1865  // Report is for an invoice. Hence, we get a number of the invoice.
1866  report_number = gncInvoiceGetID(invoice);
1867  }
1868  }
1869 
1870  if (report_name && job_date)
1871  {
1872  // Look up the sprintf format of the output name from the preferences database
1873  char* format = gnc_prefs_get_string(GNC_PREFS_GROUP_REPORT_PDFEXPORT, GNC_PREF_FILENAME_FMT);
1874 
1875  if (format && *format)
1876  {
1877  job_name = g_strdup_printf(format, report_name,
1878  report_number, job_date);
1879  }
1880  else
1881  {
1882  PWARN("No GNC_PREF_FILENAME_FMT!");
1883  job_name = g_strdup_printf ("%s %s %s", report_name,
1884  report_number, job_date);
1885  }
1886  g_free(format);
1887  }
1888  g_free (report_name);
1889  g_free (job_date);
1890 
1891  {
1892  char forbidden_char = '/';
1893  // Now remove the characters that are not allowed in file
1894  // names. FIXME: Check for all disallowed characters here!
1895  while (strchr(job_name, forbidden_char))
1896  {
1897  *strchr(job_name, forbidden_char) = '_';
1898  }
1899  }
1900 
1901  {
1902  /* And one final checking issue: We want to avoid allocating
1903  * the same name twice for a saved PDF. Hence, we keep a
1904  * GHashTable with the usage count of existing output
1905  * names. (Because I'm lazy, I just use a static GHashTable
1906  * for this.) */
1907  gpointer value;
1908  gboolean already_found;
1909  g_assert(static_report_printnames);
1910 
1911  // Lookup the existing usage count
1912  value = g_hash_table_lookup(static_report_printnames, job_name);
1913  already_found = (value != NULL);
1914  if (!value)
1915  {
1916  value = GINT_TO_POINTER(0);
1917  }
1918 
1919  // Increment the stored usage count
1920  value = GINT_TO_POINTER(1 + GPOINTER_TO_INT(value));
1921  // and store it again
1922  g_hash_table_insert(static_report_printnames, g_strdup(job_name), value);
1923 
1924  // If the previous usage count was more than 0, append the current
1925  // count (which is now 2 or higher) to the resulting name
1926  if (already_found)
1927  {
1928  // The name was already in use, so modify the name again
1929  gchar *tmp = g_strdup_printf("%s_%d", job_name, (int) GPOINTER_TO_INT(value));
1930  g_free(job_name);
1931  job_name = tmp;
1932  }
1933  }
1934 
1935  return job_name;
1936 }
1937 
1938 static void
1939 gnc_plugin_page_report_print_cb( GtkAction *action, GncPluginPageReport *report )
1940 {
1941  GncPluginPageReportPrivate *priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1942  gchar *job_name = report_create_jobname(priv);
1943 
1944  //g_warning("Setting job name=%s", job_name);
1945 
1946 #ifdef WEBKIT1
1947  gnc_html_print (priv->html, job_name, FALSE);
1948 #else
1949  gnc_html_print (priv->html, job_name);
1950 #endif
1951 
1952  g_free (job_name);
1953 }
1954 
1955 static void
1956 gnc_plugin_page_report_exportpdf_cb( GtkAction *action, GncPluginPageReport *report )
1957 {
1958  GncPluginPageReportPrivate *priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1959  gchar *job_name = report_create_jobname(priv);
1960  GncInvoice *invoice;
1961  GncOwner *owner = NULL;
1962 
1963  // Do we have an invoice report?
1964  invoice = lookup_invoice(priv);
1965  if (invoice)
1966  {
1967  // Does this invoice also have an owner?
1968  owner = (GncOwner*) gncInvoiceGetOwner(invoice);
1969  if (owner)
1970  {
1971  QofInstance *inst = qofOwnerGetOwner (owner);
1972  gchar *dirname = NULL;
1973  qof_instance_get (inst, "export-pdf-dir", &dirname, NULL);
1974  // Yes. In the kvp, look up the key for the Export-PDF output
1975  // directory. If it exists, prepend this to the job name so that
1976  // we can export to PDF.
1977  if (dirname)
1978  {
1979  if (g_file_test (dirname, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
1980  {
1981  gchar *tmp = g_build_filename (dirname, job_name, NULL);
1982  g_free (job_name);
1983  job_name = tmp;
1984  }
1985  g_free (dirname);
1986  }
1987  }
1988  }
1989 
1990  //g_warning("Setting job name=%s", job_name);
1991 
1992 #ifdef WEBKIT1
1993  gnc_html_print (priv->html, job_name, TRUE);
1994 #else
1995  gnc_html_print (priv->html, job_name);
1996 #endif
1997 
1998  if (owner)
1999  {
2000  /* As this is an invoice report with some owner, we will try
2001  * to look up the chosen output directory from the print
2002  * settings and store it again in the owner kvp.
2003  */
2004  GtkPrintSettings *print_settings = gnc_print_get_settings();
2005  if (print_settings &&
2006  gtk_print_settings_has_key(print_settings,
2008  {
2009  const char* dirname = gtk_print_settings_get(print_settings,
2011  // Only store the directory if it exists.
2012  if (g_file_test(dirname, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
2013  {
2014  QofInstance *inst = qofOwnerGetOwner(owner);
2015  gncOwnerBeginEdit(owner);
2016  qof_instance_set (inst, "export-pdf-dir", dirname);
2017  gncOwnerCommitEdit(owner);
2018  }
2019  }
2020  }
2021 
2022  g_free (job_name);
2023 }
2024 
2025 static void
2026 gnc_plugin_page_report_copy_cb(GtkAction *action, GncPluginPageReport *report)
2027 {
2029 
2030  priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
2031  gnc_html_copy_to_clipboard(priv->html);
2032 }
2033 
2034 /********************************************************************
2035  * gnc_main_window_open_report()
2036  * open an report in a top level window from an ID number
2037  ********************************************************************/
2038 
2039 void
2040 gnc_main_window_open_report(int report_id, GncMainWindow *window)
2041 {
2042  GncPluginPage *reportPage;
2043 
2044  if (window)
2045  g_return_if_fail(GNC_IS_MAIN_WINDOW(window));
2046 
2047  reportPage = gnc_plugin_page_report_new( report_id );
2048  gnc_main_window_open_page( window, reportPage );
2049 }
2050 
2051 void
2052 gnc_main_window_open_report_url(const char * url, GncMainWindow *window)
2053 {
2054  GncPluginPage *reportPage;
2055 
2056  DEBUG( "report url: [%s]\n", url );
2057 
2058  if (window)
2059  g_return_if_fail(GNC_IS_MAIN_WINDOW(window));
2060 
2061  reportPage = gnc_plugin_page_report_new( 42 /* url? */ );
2062  gnc_main_window_open_page( window, reportPage );
2063 }
2064 
ISO: yyyy-mm-dd.
Definition: gnc-date.h:133
GncHtml * html
the gnc_html abstraction this PluginPage contains
GtkWidget * gnc_plugin_page_get_window(GncPluginPage *page)
Retrieve a pointer to the GncMainWindow (GtkWindow) containing this page.
const gchar * tab_icon
The relative name of the icon that should be shown on the tab for this page.
GtkContainer * container
the container the above HTML widget is in.
gboolean(* focus_page_function)(GncPluginPage *plugin_page)
This function performs specific actions to set the focus on a specific widget.
void qof_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
The instance data structure for a content plugin.
gchar * gnc_prefs_get_string(const gchar *group, const gchar *pref_name)
Get a string value from the preferences backend.
gchar * gnc_build_userdata_path(const gchar *filename)
Make a path to filename in the user&#39;s gnucash data directory.
#define GNC_GTK_PRINT_SETTINGS_EXPORT_DIR
Key for saving the PDF-export directory in the print settings.
Definition: print-session.h:70
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
utility functions for the GnuCash UI
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
GncPluginPage *(* recreate_page)(GtkWidget *window, GKeyFile *file, const gchar *group)
Create a new page based on the information saved during a previous instantiation of gnucash...
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
const gchar * gnc_plugin_page_get_page_name(GncPluginPage *page)
Retrieve the name of this page.
Functions that are supported by all types of windows.
void qof_instance_set(QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_set Group setting multiple parameters in a single begin/commit/rollback.
A structure for defining alternate action names for use in the toolbar.
Definition: gnc-plugin.h:228
void gnc_utf8_strip_invalid_and_controls(gchar *str)
Strip any non-utf8 characters and any control characters (everything < 0x20, , , ...
GtkWidget * window
The window that contains the display widget for this plugin.
gboolean gnc_main_window_is_restoring_pages(GncMainWindow *window)
Check if the main window is restoring the plugin pages.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
void gncOwnerBeginEdit(GncOwner *owner)
These are convenience wrappers around gnc{Vendor,Customer,Job,Employee}* functions.
Definition: gncOwner.c:73
GncPluginPage * gnc_main_window_get_current_page(GncMainWindow *window)
Retrieve a pointer to the page that is currently at the front of the specified window.
void gnc_main_window_open_page(GncMainWindow *window, GncPluginPage *page)
Display a data plugin page in a window.
QofInstance * qofOwnerGetOwner(const GncOwner *owner)
return the owner itself as an entity.
Definition: gncOwner.c:276
void(* update_edit_menu_actions)(GncPluginPage *plugin_page, gboolean hide)
This function vector allows page specific actions to override the generic code for setting the sensit...
void(* destroy_widget)(GncPluginPage *plugin_page)
Function called to destroy the display widget for a particular type of plugin.
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
This file contains the functions to present a GUI to manage custom reports.
The class data structure for a content plugin.
Functions providing the file history menu.
void gnc_plugin_page_disconnect_page_changed(GncPluginPage *page)
Disconnect the page_changed_id signal callback.
void gnc_plugin_init_short_names(GtkActionGroup *action_group, action_toolbar_labels *toolbar_labels)
Add "short" labels to existing actions.
Definition: gnc-plugin.c:234
char * gnc_print_time64(time64 time, const char *format)
print a time64 as a date string per format
Definition: gnc-date.cpp:379
const gchar * plugin_name
The textual name of this plugin.
GtkWidget *(* create_widget)(GncPluginPage *plugin_page)
Function called to create the display widget for a particular type of plugin.
void(* page_name_changed)(GncPluginPage *plugin_page, const gchar *name)
This function vector allows page specific actions to occur when the page name is changed.
Gnome specific utility functions.
gboolean(* finish_pending)(GncPluginPage *plugin_page)
This function vector is called to finish any outstanding activities.
All type declarations for the whole Gnucash engine.
void(* save_page)(GncPluginPage *page, GKeyFile *file, const gchar *group)
Save enough information about this page so that it can be recreated next time the user starts gnucash...
GncPluginPage * gnc_plugin_page_report_new(int reportId)
GtkPrintSettings * gnc_print_get_settings()
Returns the pointer to our static GtkPrintSettings object.
GLib helper routines.
Generic api to store and retrieve preferences.
GNCOptionDB * cur_odb
The Option DB for this report.
GtkAction * gnc_plugin_page_get_action(GncPluginPage *page, const gchar *name)
Retrieve a GtkAction object associated with this page.
void gnc_plugin_update_actions(GtkActionGroup *action_group, const gchar **action_names, const gchar *property_name, gboolean value)
Update a property on a set of existing GtkActions.
Definition: gnc-plugin.c:280
SCM cur_report
The report which this Page is satisfying.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
void gnc_plugin_page_inserted_cb(GncPluginPage *page, gpointer user_data)
Set up the page_changed callback for when the current page is changed.
void gnc_main_window_close_page(GncPluginPage *page)
Remove a data plugin page from a window and display the previous page.
Functions for adding plugins to a GnuCash window.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
time64 gnc_time(time64 *tbuf)
get the current local time
Definition: gnc-date.cpp:273
void gnc_plugin_page_add_book(GncPluginPage *page, QofBook *book)
Add a book reference to the specified page.
GtkActionGroup * gnc_plugin_page_create_action_group(GncPluginPage *page, const gchar *group_name)
Create the GtkActionGroup object associated with this page.
The instance data structure for a main window object.
File path resolution utility functions.
gboolean gnc_date_string_to_dateformat(const gchar *format_string, QofDateFormat *format)
Converts the date format to a printable string.
const gchar * qof_date_format_get_string(QofDateFormat df)
This function returns a strftime formatting string for printing an all numeric date (e...
Definition: gnc-date.cpp:509
void main_window_update_page_name(GncPluginPage *page, const gchar *name_in)
Update the name of the page in the main window.
QofDateFormat
Enum for determining a date format.
Definition: gnc-date.h:128
#define SCHEME_OPTIONS
The key name used it the state file for storing the report options.