GnuCash c935c2f+
Loading...
Searching...
No Matches
Files | Data Structures | Macros | Enumerations | Functions
Reports

Files

file  gnc-plugin-page-report.h
 Report page.
 

Data Structures

struct  GncPluginPageReportPrivate
 
struct  GncPluginPageReport
 
struct  GncPluginPageReportClass
 

Macros

#define GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(o)    ((GncPluginPageReportPrivate*)gnc_plugin_page_report_get_instance_private((GncPluginPageReport*)o))
 
#define SCHEME_OPTIONS   "SchemeOptions"
 The key name used it the state file for storing the report options.
 
#define SCHEME_OPTIONS_N   "SchemeOptions%d"
 
#define GNC_PREFS_GROUP_REPORT_PDFEXPORT   GNC_PREFS_GROUP_GENERAL_REPORT ".pdf-export"
 
#define GNC_PREF_FILENAME_DATE_FMT   "filename-date-format"
 
#define GNC_PREF_FILENAME_FMT   "filename-format"
 
#define GNC_TYPE_PLUGIN_PAGE_REPORT   (gnc_plugin_page_report_get_type ())
 
#define GNC_PLUGIN_PAGE_REPORT(obj)   (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNC_TYPE_PLUGIN_PAGE_REPORT, GncPluginPageReport))
 
#define GNC_PLUGIN_PAGE_REPORT_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST ((klass), GNC_TYPE_PLUGIN_PAGE_REPORT, GncPluginPageReportClass))
 
#define GNC_IS_PLUGIN_PAGE_REPORT(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNC_TYPE_PLUGIN_PAGE_REPORT))
 
#define GNC_IS_PLUGIN_PAGE_REPORT_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GNC_TYPE_PLUGIN_PAGE_REPORT))
 
#define GNC_PLUGIN_PAGE_REPORT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GNC_TYPE_PLUGIN_PAGE_REPORT, GncPluginPageReportClass))
 
#define GNC_PLUGIN_PAGE_REPORT_NAME   "GncPluginPageReport"
 
#define WINDOW_REPORT_CM_CLASS   "window-report"
 

Enumerations

enum  { PROP_0 , PROP_REPORT_ID }
 

Functions

void gnc_plugin_page_report_destroy (GncPluginPageReportPrivate *priv)
 
void gnc_plugin_page_report_remove_edited_report (GncPluginPageReportPrivate *priv, SCM report)
 
void gnc_plugin_page_report_add_edited_report (GncPluginPageReportPrivate *priv, SCM report)
 
void gnc_plugin_page_report_raise_editor (SCM report)
 
GncPluginPagegnc_plugin_page_report_new (int reportId)
 
void gnc_plugin_page_report_reload (GncPluginPageReport *report)
 
void gnc_main_window_open_report (int report_id, GncMainWindow *window)
 
void gnc_main_window_open_report_url (const char *url, GncMainWindow *window)
 
GType gnc_plugin_page_report_get_type (void)
 

Detailed Description

Macro Definition Documentation

◆ GNC_IS_PLUGIN_PAGE_REPORT

#define GNC_IS_PLUGIN_PAGE_REPORT (   obj)    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNC_TYPE_PLUGIN_PAGE_REPORT))

Definition at line 49 of file gnc-plugin-page-report.h.

◆ GNC_IS_PLUGIN_PAGE_REPORT_CLASS

#define GNC_IS_PLUGIN_PAGE_REPORT_CLASS (   klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GNC_TYPE_PLUGIN_PAGE_REPORT))

Definition at line 50 of file gnc-plugin-page-report.h.

◆ GNC_PLUGIN_PAGE_REPORT

#define GNC_PLUGIN_PAGE_REPORT (   obj)    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNC_TYPE_PLUGIN_PAGE_REPORT, GncPluginPageReport))

Definition at line 47 of file gnc-plugin-page-report.h.

◆ GNC_PLUGIN_PAGE_REPORT_CLASS

#define GNC_PLUGIN_PAGE_REPORT_CLASS (   klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GNC_TYPE_PLUGIN_PAGE_REPORT, GncPluginPageReportClass))

Definition at line 48 of file gnc-plugin-page-report.h.

◆ GNC_PLUGIN_PAGE_REPORT_GET_CLASS

#define GNC_PLUGIN_PAGE_REPORT_GET_CLASS (   obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GNC_TYPE_PLUGIN_PAGE_REPORT, GncPluginPageReportClass))

Definition at line 51 of file gnc-plugin-page-report.h.

◆ GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE

#define GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE (   o)     ((GncPluginPageReportPrivate*)gnc_plugin_page_report_get_instance_private((GncPluginPageReport*)o))

Definition at line 138 of file gnc-plugin-page-report.cpp.

187{
188 { "FilePrintAction", gnc_plugin_page_report_print_cb, nullptr, nullptr, nullptr },
189 { "FilePrintPDFAction", gnc_plugin_page_report_exportpdf_cb, nullptr, nullptr, nullptr },
190 { "EditCopyAction", gnc_plugin_page_report_copy_cb, nullptr, nullptr, nullptr },
191 { "EditTaxOptionsAction", gnc_plugin_page_report_edit_tax_cb, nullptr, nullptr, nullptr },
192 { "ViewRefreshAction", gnc_plugin_page_report_reload_cb, nullptr, nullptr, nullptr },
193 { "ReportSaveAction", gnc_plugin_page_report_save_cb, nullptr, nullptr, nullptr },
194 { "ReportSaveAsAction", gnc_plugin_page_report_save_as_cb, nullptr, nullptr, nullptr },
195 { "ReportExportAction", gnc_plugin_page_report_export_cb, nullptr, nullptr, nullptr },
196 { "ReportOptionsAction", gnc_plugin_page_report_options_cb, nullptr, nullptr, nullptr },
197 { "ReportBackAction", gnc_plugin_page_report_back_cb, nullptr, nullptr, nullptr },
198 { "ReportForwAction", gnc_plugin_page_report_forw_cb, nullptr, nullptr, nullptr },
199 { "ReportReloadAction", gnc_plugin_page_report_reload_cb, nullptr, nullptr, nullptr },
200 { "ReportStopAction", gnc_plugin_page_report_stop_cb, nullptr, nullptr, nullptr },
201};
202static guint num_report_actions = G_N_ELEMENTS(report_actions);
203static const gchar *initially_insensitive_actions[] =
204{
205 nullptr
206};
207
208static const gchar *disable_during_load_actions[] =
209{
210 "FilePrintAction",
211 "FilePrintPDFAction",
212 "ReportOptionsAction",
213 nullptr
214};
215
217static const gchar *gnc_plugin_load_ui_items [] =
218{
219 "FilePlaceholder3",
220 "FilePlaceholder4",
221 "FilePlaceholder5",
222 "EditPlaceholder3",
223 "EditPlaceholder5",
224 "EditPlaceholder6",
225 "ViewPlaceholder4",
226 "ReportsPlaceholder1",
227 NULL,
228};
229
231static GncToolBarShortNames toolbar_labels[] =
232{
233 { "FilePrintAction", N_("Print") },
234 { "ReportExportAction", N_("Export") },
235 { "ReportOptionsAction", N_("Options") },
236 /* Translators: This string is meant to be a short alternative for "Save Report Configuration"
237 to be used as toolbar button label. */
238 { "ReportSaveAction", N_("Save Config") },
239 /* Translators: This string is meant to be a short alternative for "Save Report Configuration As…"
240 to be used as toolbar button label. */
241 { "ReportSaveAsAction", N_("Save Config As…") },
242 { "FilePrintPDFAction", N_("Export as PDF") },
243 { nullptr, nullptr },
244};
245
246static void
247gnc_plugin_page_report_get_property( GObject *obj,
248 guint prop_id,
249 GValue *value,
250 GParamSpec *pspec )
251{
254
255 rep = GNC_PLUGIN_PAGE_REPORT( obj );
256 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(rep);
257
258 switch ( prop_id )
259 {
260 case PROP_REPORT_ID:
261 g_value_set_int( value, priv->reportId );
262 break;
263 default:
264 PERR( "Unknown property id %d", prop_id );
265 break;
266 }
267}
268
269static void
270gnc_plugin_page_report_set_property( GObject *obj,
271 guint prop_id,
272 const GValue *value,
273 GParamSpec *pspec )
274{
277
278 rep = GNC_PLUGIN_PAGE_REPORT( obj );
279 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(rep);
280
281 DEBUG( "setting property with id %d / %p to value %d",
282 prop_id, priv, g_value_get_int( value ) );
283
284 switch ( prop_id )
285 {
286 case PROP_REPORT_ID:
287 priv->reportId = g_value_get_int( value );
288 break;
289 default:
290 PERR( "unknown property id %d", prop_id );
291 break;
292 }
293
294}
295
300static gboolean
301gnc_plugin_page_report_focus_widget (GncPluginPage *report_plugin_page)
302{
303 if (GNC_IS_PLUGIN_PAGE_REPORT(report_plugin_page))
304 {
305 GncPluginPageReportPrivate *priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report_plugin_page);
306 GtkWidget *window;
307 GAction *action;
308
309 if (!priv)
310 return FALSE;
311
312 /* Disable the Transaction Menu */
313 action = gnc_main_window_find_action (GNC_MAIN_WINDOW(report_plugin_page->window), "TransactionAction");
314 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), FALSE);
315 /* Disable the Schedule menu */
316 action = gnc_main_window_find_action (GNC_MAIN_WINDOW(report_plugin_page->window), "ScheduledAction");
317 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), FALSE);
318
319 gnc_main_window_update_menu_and_toolbar (GNC_MAIN_WINDOW(report_plugin_page->window),
320 report_plugin_page,
321 gnc_plugin_load_ui_items);
322
323 // setup any short toolbar names
324 gnc_main_window_init_short_names (GNC_MAIN_WINDOW(report_plugin_page->window), toolbar_labels);
325
326 gnc_plugin_page_report_menu_updates (report_plugin_page);
327
328 window = gnc_plugin_page_get_window (report_plugin_page);
329
330 if (window && !gnc_main_window_is_restoring_pages (GNC_MAIN_WINDOW(window)))
331 {
332 GtkWidget *widget = gnc_html_get_webview (priv->html);
333
334 if (!priv->loaded) // so we only do the load once
335 gnc_plugin_page_report_load_uri (report_plugin_page);
336
337 if (widget && GTK_IS_WIDGET(widget))
338 {
339 if (!gtk_widget_is_focus (GTK_WIDGET(widget)))
340 gtk_widget_grab_focus (GTK_WIDGET(widget));
341 }
342 }
343 }
344 return FALSE;
345}
346
347static void
348gnc_plugin_page_report_class_init (GncPluginPageReportClass *klass)
349{
350 GObjectClass *object_class = G_OBJECT_CLASS (klass);
351 GncPluginPageClass *gnc_plugin_page_class = GNC_PLUGIN_PAGE_CLASS(klass);
352
353 object_class->constructor = gnc_plugin_page_report_constructor;
354 object_class->finalize = gnc_plugin_page_report_finalize;
355
356 object_class->set_property = gnc_plugin_page_report_set_property;
357 object_class->get_property = gnc_plugin_page_report_get_property;
358
359 gnc_plugin_page_class->tab_icon = GNC_ICON_ACCOUNT_REPORT;
360 gnc_plugin_page_class->plugin_name = GNC_PLUGIN_PAGE_REPORT_NAME;
361
362 gnc_plugin_page_class->create_widget = gnc_plugin_page_report_create_widget;
363 gnc_plugin_page_class->destroy_widget = gnc_plugin_page_report_destroy_widget;
364 gnc_plugin_page_class->save_page = gnc_plugin_page_report_save_page;
365 gnc_plugin_page_class->recreate_page = gnc_plugin_page_report_recreate_page;
366 gnc_plugin_page_class->page_name_changed = gnc_plugin_page_report_name_changed;
367 gnc_plugin_page_class->update_edit_menu_actions = gnc_plugin_page_report_update_edit_menu;
368 gnc_plugin_page_class->finish_pending = gnc_plugin_page_report_finish_pending;
369 gnc_plugin_page_class->focus_page_function = gnc_plugin_page_report_focus_widget;
370
371 // create the "reportId" property
372 auto paramspec{static_cast<GParamFlags>(G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)};
373 g_object_class_install_property( object_class,
374 PROP_REPORT_ID,
375 g_param_spec_int( "report-id",
376 _("The numeric ID of the report."),
377 _("The numeric ID of the report."),
378 -1, G_MAXINT, -1,
379 paramspec));
380}
381
382static void
383gnc_plugin_page_report_finalize (GObject *object)
384{
385 g_return_if_fail (GNC_IS_PLUGIN_PAGE_REPORT (object));
386
387 ENTER("object %p", object);
388 G_OBJECT_CLASS (gnc_plugin_page_report_parent_class)->finalize (object);
389 LEAVE(" ");
390}
391
392static void
393gnc_plugin_page_report_set_progressbar (GncPluginPage *page, gboolean set)
394{
395 GtkWidget *progressbar;
396 GtkAllocation allocation;
397
398 progressbar = gnc_window_get_progressbar (GNC_WINDOW(page->window));
399 gtk_widget_get_allocation (GTK_WIDGET(progressbar), &allocation);
400
401 // this sets the minimum size of the progressbar to that allocated
402 if (set)
403 gtk_widget_set_size_request (GTK_WIDGET(progressbar), -1, allocation.height);
404 else
405 gtk_widget_set_size_request (GTK_WIDGET(progressbar), -1, -1); //reset
406}
407
408static void
409gnc_plugin_page_report_load_uri (GncPluginPage *page)
410{
411 GncPluginPageReport *report;
413 GncPluginPage *weak_page = page;
414 URLType type;
415 char * id_name;
416 char * child_name;
417 char * url_location = nullptr;
418 char * url_label = nullptr;
419
420 report = GNC_PLUGIN_PAGE_REPORT(page);
421 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
422 if (!priv)
423 return; // No priv means the page doesn't exist anymore.
424
425 DEBUG( "Load uri id=%d", priv->reportId );
426 id_name = g_strdup_printf("id=%d", priv->reportId );
427 child_name = gnc_build_url( URL_TYPE_REPORT, id_name, nullptr );
428 type = gnc_html_parse_url( priv->html, child_name, &url_location, &url_label);
429 DEBUG( "passing id_name=[%s] child_name=[%s] type=[%s], location=[%s], label=[%s]",
430 id_name, child_name ? child_name : "(null)",
431 type ? type : "(null)", url_location ? url_location : "(null)",
432 url_label ? url_label : "(null)" );
433
434 g_free(id_name);
435 g_free(child_name);
436
437 g_object_add_weak_pointer(G_OBJECT(page), (gpointer*)(&weak_page));
438 gtk_widget_show_all( GTK_WIDGET(priv->container) );
439
440 priv->loaded = TRUE;
441
442 // this sets the window for the progressbar
443 gnc_window_set_progressbar_window( GNC_WINDOW(page->window) );
444
445 // this sets the minimum size of the progressbar to that allocated
446 gnc_plugin_page_report_set_progressbar( page, TRUE );
447
448 gnc_html_show_url(priv->html, type, url_location, url_label, 0);
449 g_free(url_location);
450
451 if (weak_page)
452 {
453 gnc_plugin_page_report_set_progressbar( page, FALSE );
454 g_object_remove_weak_pointer(G_OBJECT(page), (gpointer*)(&weak_page));
455 }
456
457 gnc_plugin_set_actions_enabled(G_ACTION_MAP(priv->action_group),
458 disable_during_load_actions, TRUE);
459 // this resets the window for the progressbar to nullptr
460 gnc_window_set_progressbar_window( nullptr );
461}
462
463/* used to capture Ctrl+Alt+PgUp/Down for tab selection */
464static gboolean
465webkit_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
466{
467 GncPluginPageReport *report = GNC_PLUGIN_PAGE_REPORT(user_data);
468 GncPluginPageReportPrivate *priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
469 GdkModifierType modifiers = gtk_accelerator_get_default_mod_mask ();
470 GtkWidget *window = gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(report));
471
472 if (GNC_PLUGIN_PAGE(report) != gnc_main_window_get_current_page (GNC_MAIN_WINDOW(window)))
473 return FALSE;
474
475 if ((event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_Page_Down ||
476 event->keyval == GDK_KEY_KP_Page_Up || event->keyval == GDK_KEY_KP_Page_Down)
477 && (event->state & modifiers) == (GDK_CONTROL_MASK | GDK_MOD1_MASK))
478 {
479 GtkNotebook *notebook = GTK_NOTEBOOK(gtk_widget_get_parent (GTK_WIDGET(priv->container)));
480 gint pages = gtk_notebook_get_n_pages (notebook);
481 gint current_page = gtk_notebook_get_current_page (notebook);
482
483 if (event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_KP_Page_Up)
484 {
485 if (current_page == 0)
486 gtk_notebook_set_current_page (notebook, pages - 1);
487 else
488 gtk_notebook_prev_page (notebook);
489 }
490 else
491 {
492 if (pages == current_page + 1)
493 gtk_notebook_set_current_page (notebook, 0);
494 else
495 gtk_notebook_next_page (notebook);
496 }
497 return TRUE;
498 }
499 return FALSE;
500}
501
502static
503GtkWidget*
504gnc_plugin_page_report_create_widget( GncPluginPage *page )
505{
506 GncPluginPageReport *report;
508 GtkWindow *topLvl;
509 GtkWidget *webview;
510 URLType type;
511 char * id_name;
512 char * child_name;
513 char * url_location = nullptr;
514 char * url_label = nullptr;
515
516 ENTER("page %p", page);
517
518 report = GNC_PLUGIN_PAGE_REPORT(page);
519 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
520
521#ifndef WEBKIT1
522 /* Hide the ExportPdf action for Webkit2 */
523 priv->webkit2 = TRUE;
524#endif
525
526 topLvl = gnc_ui_get_main_window (nullptr);
527// priv->html = gnc_html_new( topLvl );
528 priv->html = gnc_html_factory_create_html();
529 gnc_html_set_parent( priv->html, topLvl );
530 priv->loaded = FALSE;
531
532 gnc_html_history_set_node_destroy_cb(gnc_html_get_history(priv->html),
533 gnc_plugin_page_report_history_destroy_cb,
534 (gpointer)priv);
535
536 priv->container = GTK_CONTAINER(gtk_frame_new(nullptr));
537 gtk_frame_set_shadow_type(GTK_FRAME(priv->container), GTK_SHADOW_NONE);
538
539 // Set the name for this widget so it can be easily manipulated with css
540 gtk_widget_set_name (GTK_WIDGET(priv->container), "gnc-id-report-page");
541
542 gtk_container_add(GTK_CONTAINER(priv->container),
543 gnc_html_get_widget(priv->html));
544
545 priv->component_manager_id =
546 gnc_register_gui_component(WINDOW_REPORT_CM_CLASS, nullptr,
547 close_handler, page);
548 gnc_gui_component_set_session(priv->component_manager_id,
549 gnc_get_current_session());
550
551 gnc_html_set_urltype_cb(priv->html, gnc_plugin_page_report_check_urltype);
552 gnc_html_set_load_cb(priv->html, gnc_plugin_page_report_load_cb, report);
553
554 /* We need to call the load call back so the report appears to have been run
555 so it will get saved properly if the report is not realized in session */
556 id_name = g_strdup_printf("id=%d", priv->reportId );
557 child_name = gnc_build_url( URL_TYPE_REPORT, id_name, nullptr );
558 type = gnc_html_parse_url( priv->html, child_name, &url_location, &url_label);
559
560 gnc_plugin_page_report_load_cb (priv->html, type, id_name, url_label, report);
561 g_free(id_name);
562 g_free(child_name);
563 g_free (url_label);
564 g_free (url_location);
565
566 // FIXME. This is f^-1(f(x)), isn't it?
567 DEBUG( "id=%d", priv->reportId );
568
569 g_signal_connect (G_OBJECT(page), "inserted",
570 G_CALLBACK(gnc_plugin_page_inserted_cb),
571 nullptr);
572
573 // used to capture Ctrl+Alt+PgUp/Down for tab selection
574 webview = gnc_html_get_webview (priv->html);
575 if (webview)
576 {
577 gtk_widget_add_events (webview, gtk_widget_get_events (webview) |
578 GDK_KEY_PRESS_MASK);
579
580 g_signal_connect (webview, "key-press-event",
581 G_CALLBACK(webkit_key_press_event_cb),
582 page);
583 }
584
585 gtk_widget_show_all( GTK_WIDGET(priv->container) );
586 LEAVE("container %p", priv->container);
587 return GTK_WIDGET( priv->container );
588}
589
590/********************************************************************
591 * gnc_plugin_page_report_check_urltype
592 * is it OK to show a certain URLType in this window?
593 ********************************************************************/
594static int
595gnc_plugin_page_report_check_urltype(URLType t)
596{
597 if (!g_strcmp0 (t, URL_TYPE_REPORT))
598 {
599 return TRUE;
600 }
601 else
602 {
603 return FALSE;
604 }
605}
606
611static void
612gnc_plugin_page_report_setup( GncPluginPage *ppage )
613{
614 GncPluginPageReport *report = GNC_PLUGIN_PAGE_REPORT(ppage);
616 SCM set_needs_save = scm_c_eval_string("gnc:report-set-needs-save?!");
617 SCM inst_report;
618 int report_id;
619
620 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
621 priv->cur_report = SCM_BOOL_F;
622 priv->initial_report = SCM_BOOL_F;
623 priv->edited_reports = SCM_EOL;
624 priv->name_change_cb_id = 0;
625
626 g_object_get( ppage, "report-id", &report_id, nullptr );
627
628 PINFO("report-id: %d\n", report_id);
629
630 /* get the inst-report from the Scheme-side hash, and get its
631 * options and editor thunk */
632 if ((inst_report = gnc_report_find(report_id)) == SCM_BOOL_F)
633 {
634 return;
635 }
636
637 if (priv->initial_report == SCM_BOOL_F)
638 {
639 priv->initial_report = inst_report;
640 scm_gc_protect_object(priv->initial_report);
641 }
642
643 // all reports need [to be] saved immediately after they're created.
644 PINFO("set needs save");
645 scm_call_2(set_needs_save, inst_report, SCM_BOOL_T);
646}
647
648/********************************************************************
649 * gnc_plugin_page_report_load_cb
650 * called after a report is loaded into the gnc_html widget
651 ********************************************************************/
652static void
653gnc_plugin_page_report_load_cb (GncHtml * html, URLType type,
654 const gchar * location, const gchar * label,
655 gpointer data)
656{
657 GncPluginPageReport *report = GNC_PLUGIN_PAGE_REPORT(data);
659 int report_id;
660 SCM set_needs_save = scm_c_eval_string("gnc:report-set-needs-save?!");
661 SCM inst_report;
662
663 ENTER( "load_cb: type=[%s], location=[%s], label=[%s]",
664 type ? type : "(null)", location ? location : "(null)",
665 label ? label : "(null)" );
666
667 /* we get this callback if a new report is requested to be loaded OR
668 * if any URL is clicked. If an options URL is clicked, we want to
669 * know about it */
670 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
671 if (!g_strcmp0 (type, URL_TYPE_REPORT)
672 && location
673 && (strlen(location) > 3)
674 && !strncmp("id=", location, 3))
675 {
676 report_id = gnc_report_id_string_to_report_id (location + 3);
677 if (report_id < 0)
678 {
679 LEAVE ("id_string error %s", location);
680 return;
681 }
682 DEBUG( "parsed id=%d", report_id );
683 }
684 else if (!g_strcmp0( type, URL_TYPE_OPTIONS)
685 && location
686 && (strlen(location) > 10)
687 && !strncmp("report-id=", location, 10))
688 {
689 report_id = atoi(location + 10);
690 inst_report = gnc_report_find(report_id);
691 if (inst_report != SCM_BOOL_F)
692 {
693 gnc_plugin_page_report_add_edited_report(priv, inst_report);
694 }
695 LEAVE("");
696 return;
697 }
698 else
699 {
700 LEAVE( " unknown URL type [%s] location [%s]", type, location );
701 return;
702 }
703
704 /* get the inst-report from the hash, and get its
705 * options and editor thunk */
706 if ((inst_report = gnc_report_find(report_id)) == SCM_BOOL_F)
707 {
708 LEAVE( "error getting inst_report" );
709 return;
710 }
711
712 if (priv->initial_report == SCM_BOOL_F)
713 {
714 priv->initial_report = inst_report;
715 scm_gc_protect_object(priv->initial_report);
716
717 DEBUG("calling set_needs_save for report with id=%d", report_id);
718 scm_call_2(set_needs_save, inst_report, SCM_BOOL_T);
719
720 priv->initial_odb = gnc_get_report_optiondb(inst_report);
721
722 priv->name_change_cb_id =
723 priv->initial_odb->register_callback(
724 gnc_plugin_page_report_refresh, priv);
725
726 }
727
728 if ((priv->cur_report != SCM_BOOL_F) && (priv->cur_odb != nullptr))
729 {
730 priv->cur_odb->unregister_callback(priv->option_change_cb_id);
731 priv->option_change_cb_id = 0;
732 priv->cur_odb = nullptr;
733 }
734
735 if (priv->cur_report != SCM_BOOL_F)
736 scm_gc_unprotect_object(priv->cur_report);
737 priv->cur_report = inst_report;
738 scm_gc_protect_object(priv->cur_report);
739
740 priv->cur_odb = gnc_get_report_optiondb(inst_report);
741
742 priv->option_change_cb_id =
743 priv->cur_odb->register_callback(
744 gnc_plugin_page_report_option_change_cb, report);
745
746 if (gnc_html_history_forward_p(gnc_html_get_history(priv->html)))
747 {
748 gnc_plugin_page_report_set_fwd_button(report, TRUE);
749 }
750 else
751 {
752 gnc_plugin_page_report_set_fwd_button(report, FALSE);
753 }
754
755 if (gnc_html_history_back_p(gnc_html_get_history(priv->html)))
756 {
757 gnc_plugin_page_report_set_back_button(report, TRUE);
758 }
759 else
760 {
761 gnc_plugin_page_report_set_back_button(report, FALSE);
762 }
763
764 LEAVE( "done" );
765}
766
767
779static void
780gnc_plugin_page_report_option_change_cb(gpointer data)
781{
782 GncPluginPage *page;
783 GncPluginPageReport *report;
785 SCM dirty_report = scm_c_eval_string("gnc:report-set-dirty?!");
786
787 g_return_if_fail(GNC_IS_PLUGIN_PAGE_REPORT(data));
788 report = GNC_PLUGIN_PAGE_REPORT(data);
789 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
790 page = GNC_PLUGIN_PAGE(report);
791
792 DEBUG( "option_change" );
793 if (priv->cur_report == SCM_BOOL_F)
794 return;
795 DEBUG( "set-dirty, queue-draw" );
796
797 /* Update the page (i.e. the notebook tab and window title) */
798 std::string old_name{gnc_plugin_page_get_page_name(GNC_PLUGIN_PAGE(report))};
799 auto new_name{priv->cur_odb->lookup_string_option("General",
800 "Report name")};
801 if (new_name != old_name)
802 {
803 /* Bug 727130, 760711 - remove only the non-printable
804 * characters from the new name */
805 char *clean_name{g_strdup(new_name.c_str())};
807 ENTER("Cleaned-up new report name: %s", clean_name ? clean_name : "(null)");
808 main_window_update_page_name(GNC_PLUGIN_PAGE(report), clean_name);
809 g_free(clean_name);
810 }
811
812 /* it's probably already dirty, but make sure */
813 scm_call_2(dirty_report, priv->cur_report, SCM_BOOL_T);
814
815 gnc_plugin_set_actions_enabled(G_ACTION_MAP(priv->action_group),
816 disable_during_load_actions, FALSE);
817 // prevent closing this page while loading...
818 priv->reloading = TRUE;
819
820 // this sets the window for the progressbar
821 gnc_window_set_progressbar_window( GNC_WINDOW(page->window) );
822
823 // this sets the minimum size of the progressbar to that allocated
824 gnc_plugin_page_report_set_progressbar( page, TRUE );
825
826 /* Now queue the fact that we need to reload this report */
827 gnc_html_reload( priv->html, TRUE ); //reload by rebuild
828
829 gnc_plugin_page_report_set_progressbar( page, FALSE );
830
831 // this resets the window for the progressbar to nullptr
832 gnc_window_set_progressbar_window( nullptr );
833
834 gnc_plugin_set_actions_enabled(G_ACTION_MAP(priv->action_group),
835 disable_during_load_actions, TRUE);
836 priv->reloading = FALSE;
837}
838
839/* FIXME: This function does... nothing? */
840static void
841gnc_plugin_page_report_history_destroy_cb(gnc_html_history_node * node,
842 gpointer user_data)
843{
844#if 0
845 static SCM remover = SCM_BOOL_F;
846 int report_id;
847
848 if (remover == SCM_BOOL_F)
849 {
850 remover = scm_c_eval_string("gnc:report-remove-by-id");
851 }
852
853 if (node
854 && !g_strcmp0 (node->type, URL_TYPE_REPORT)\
855 && !strncmp("id=", node->location, 3))
856 {
857 sscanf(node->location + 3, "%d", &report_id);
858 /* printf("unreffing report %d and children\n", report_id);
859 scm_call_1(remover, scm_from_int (report_id)); */
860 }
861 else
862 {
863 return;
864 }
865#endif
866}
867
868// @param data is actually GncPluginPageReportPrivate
869static void
870gnc_plugin_page_report_refresh(gpointer data)
871{
872 // FIXME?
873 DEBUG( "report-refresh called" );
874 // something like ... gnc_plugin_page_report_redraw( nullptr, (GncPluginPageReportPrivate*)data );
875 return;
876}
877
878static void
879gnc_plugin_page_report_destroy_widget(GncPluginPage *plugin_page)
880{
882
883 // FIXME: cleanup other resources.
884
885 PINFO("destroy widget");
886 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(plugin_page);
887
888 // Remove the page_changed signal callback
889 gnc_plugin_page_disconnect_page_changed (GNC_PLUGIN_PAGE(plugin_page));
890
891 // Remove the page focus idle function if present
892 g_idle_remove_by_data (plugin_page);
893
894 if (priv->component_manager_id)
895 {
896 gnc_unregister_gui_component(priv->component_manager_id);
897 priv->component_manager_id = 0;
898 }
899
900 gnc_plugin_page_report_destroy(priv);
901 gnc_report_remove_by_id(priv->reportId);
902}
903
904
907#define SCHEME_OPTIONS "SchemeOptions"
908#define SCHEME_OPTIONS_N "SchemeOptions%d"
909
910
920static void
921gnc_plugin_page_report_save_page (GncPluginPage *plugin_page,
922 GKeyFile *key_file,
923 const gchar *group_name)
924{
925 GncPluginPageReport *report;
927 SCM gen_save_text, scm_text;
928 SCM get_embedded_list, embedded, item, tmp_report;
929 SCM get_options;
930 gint count, id;
931 gchar *text, *key_name;
932
933 g_return_if_fail (GNC_IS_PLUGIN_PAGE_REPORT(plugin_page));
934 g_return_if_fail (key_file != nullptr);
935 g_return_if_fail (group_name != nullptr);
936
937 ENTER("page %p, key_file %p, group_name %s", plugin_page, key_file,
938 group_name);
939
940 report = GNC_PLUGIN_PAGE_REPORT(plugin_page);
941 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
942
943 if (!priv || !priv->cur_report || scm_is_null(priv->cur_report) ||
944 SCM_UNBNDP(priv->cur_report) || SCM_BOOL_F == priv->cur_report)
945 {
946 LEAVE("not saving invalid report");
947 return;
948 }
949
950 gen_save_text = scm_c_eval_string("gnc:report-serialize");
951 get_embedded_list = scm_c_eval_string("gnc:report-embedded-list");
952 get_options = scm_c_eval_string("gnc:report-options");
953 embedded = scm_call_1(get_embedded_list, scm_call_1(get_options, priv->cur_report));
954 count = scm_ilength(embedded);
955 while (count-- > 0)
956 {
957 item = SCM_CAR(embedded);
958 embedded = SCM_CDR(embedded);
959 if (!scm_is_number(item))
960 continue;
961 id = scm_to_int (item);
962 tmp_report = gnc_report_find(id);
963 scm_text = scm_call_1(gen_save_text, tmp_report);
964 if (!scm_is_string (scm_text))
965 {
966 DEBUG("child report %d: nothing to save", id);
967 continue;
968 }
969
970 key_name = g_strdup_printf(SCHEME_OPTIONS_N, id);
971 text = gnc_scm_strip_comments(scm_text);
972 g_key_file_set_value(key_file, group_name, key_name, text);
973 g_free(text);
974 g_free(key_name);
975 }
976
977 scm_text = scm_call_1(gen_save_text, priv->cur_report);
978 if (!scm_is_string (scm_text))
979 {
980 LEAVE("nothing to save");
981 return;
982 }
983
984 text = gnc_scm_strip_comments(scm_text);
985 g_key_file_set_value(key_file, group_name, SCHEME_OPTIONS, text);
986 g_free(text);
987 LEAVE(" ");
988}
989
990
1000static GncPluginPage *
1001gnc_plugin_page_report_recreate_page (GtkWidget *window,
1002 GKeyFile *key_file,
1003 const gchar *group_name)
1004{
1005 GncPluginPage *page;
1006 gchar **keys;
1007 gsize i, num_keys;
1008 GError *error = nullptr;
1009 gchar *option_string;
1010 gint report_id;
1011 SCM scm_id, final_id = SCM_BOOL_F;
1012 SCM report;
1013
1014 g_return_val_if_fail(key_file, nullptr);
1015 g_return_val_if_fail(group_name, nullptr);
1016 ENTER("key_file %p, group_name %s", key_file, group_name);
1017
1018 keys = g_key_file_get_keys(key_file, group_name, &num_keys, &error);
1019 if (error)
1020 {
1021 g_warning("error reading group %s key list: %s",
1022 group_name, error->message);
1023 g_error_free(error);
1024 LEAVE("no keys");
1025 return nullptr;
1026 }
1027
1028 for (i = 0; i < num_keys; i++)
1029 {
1030 if (strncmp(keys[i], SCHEME_OPTIONS, strlen(SCHEME_OPTIONS)) != 0)
1031 continue;
1032 option_string = g_key_file_get_value(key_file, group_name,
1033 keys[i], &error);
1034 if (error)
1035 {
1036 g_warning("error reading group %s key %s: %s",
1037 group_name, keys[i], error->message);
1038 g_error_free(error);
1039 g_strfreev (keys);
1040 LEAVE("bad value");
1041 return nullptr;
1042 }
1043 scm_id = scm_eval_string(scm_from_utf8_string(option_string));
1044 g_free(option_string);
1045
1046 if (!scm_integer_p(scm_id))
1047 {
1048 DEBUG("report id not an integer for key %s", keys[i]);
1049 g_strfreev (keys);
1050 return nullptr;
1051 }
1052
1053 if (final_id == SCM_BOOL_F)
1054 {
1055 if (g_strcmp0(keys[i], SCHEME_OPTIONS) == 0)
1056 {
1057 final_id = scm_id;
1058 }
1059 }
1060 }
1061 g_strfreev (keys);
1062
1063 if (final_id == SCM_BOOL_F)
1064 {
1065 LEAVE("report not specified");
1066 return nullptr;
1067 }
1068
1069 report_id = scm_to_int(final_id);
1070 report = gnc_report_find(report_id);
1071 if (!report)
1072 {
1073 LEAVE("report doesn't exist");
1074 return nullptr;
1075 }
1076
1077 page = gnc_plugin_page_report_new( report_id );
1078
1079 LEAVE(" ");
1080 return page;
1081}
1082
1083
1094static void
1095gnc_plugin_page_report_name_changed (GncPluginPage *page, const gchar *name)
1096{
1098
1099 g_return_if_fail(GNC_IS_PLUGIN_PAGE_REPORT(page));
1100 g_return_if_fail(name != nullptr);
1101
1102 ENTER("page %p, name %s", page, name);
1103 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(page);
1104
1105 if (priv->cur_odb)
1106 {
1107
1108 /* Is this a redundant call? */
1109 auto old_name = priv->cur_odb->lookup_string_option("General",
1110 "Report name");
1111 std::string name_str{name};
1112 DEBUG("Comparing old name '%s' to new name '%s'",
1113 old_name.empty() ? "(null)" : old_name.c_str(), name);
1114 if (old_name == name_str)
1115 {
1116 LEAVE("no change");
1117 return;
1118 }
1119
1120 /* Store the new name for the report. */
1121 priv->cur_odb->set_string_option("General", "Report name", name_str);
1122
1123 }
1124
1125 /* Have to manually call the option change hook. */
1126 gnc_plugin_page_report_option_change_cb(page);
1127 LEAVE(" ");
1128}
1129
1130static void
1131gnc_plugin_page_report_update_edit_menu (GncPluginPage *page, gboolean hide)
1132{
1133 GncMainWindow *window = (GncMainWindow*)gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(page));
1134 GAction *action;
1135
1136 action = gnc_main_window_find_action (window, "EditCopyAction");
1137 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), TRUE);
1138 action = gnc_main_window_find_action (window, "EditCutAction");
1139 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), FALSE);
1140 action = gnc_main_window_find_action (window, "EditPasteAction");
1141 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), FALSE);
1142}
1143
1144static gboolean
1145gnc_plugin_page_report_finish_pending (GncPluginPage *page)
1146{
1148 GncPluginPageReport *report;
1149
1150 report = GNC_PLUGIN_PAGE_REPORT(page);
1151 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1152 return !priv->reloading;
1153}
1154
1155
1156/********************************************************************
1157 * gnc_report_window_destroy
1158 * free and destroy a window
1159 ********************************************************************/
1160void
1161gnc_plugin_page_report_destroy(GncPluginPageReportPrivate * priv)
1162{
1163 SCM get_editor = scm_c_eval_string("gnc:report-editor-widget");
1164 SCM set_editor = scm_c_eval_string("gnc:report-set-editor-widget!");
1165 SCM edited, editor;
1166
1167 /* close any open editors */
1168 for (edited = scm_list_copy(priv->edited_reports); !scm_is_null(edited);
1169 edited = SCM_CDR(edited))
1170 {
1171 editor = scm_call_1(get_editor, SCM_CAR(edited));
1172 scm_call_2(set_editor, SCM_CAR(edited), SCM_BOOL_F);
1173 if (editor != SCM_BOOL_F)
1174 {
1175#define FUNC_NAME "gtk_widget_destroy"
1176 auto w{static_cast<GtkWidget*>(SWIG_MustGetPtr(editor, SWIG_TypeQuery("_p_GtkWidget"), 1, 0))};
1177#undef FUNC_NAME
1178 gtk_widget_destroy(GTK_WIDGET(w));
1179 }
1180 }
1181
1182 if (priv->initial_odb)
1183 {
1184//Remove this if there's a double-free
1185 gnc_option_db_destroy(priv->initial_odb);
1186 priv->initial_odb = nullptr;
1187 }
1188
1189 gnc_html_destroy(priv->html);
1190 priv->html = nullptr;
1191
1192 g_object_unref(priv->container);
1193 priv->container = nullptr;
1194
1195 if (priv->cur_report != SCM_BOOL_F)
1196 scm_gc_unprotect_object(priv->cur_report);
1197 if (priv->edited_reports != SCM_EOL)
1198 scm_gc_unprotect_object(priv->edited_reports);
1199}
1200
1201static void
1202gnc_plugin_page_report_init ( GncPluginPageReport *plugin_page )
1203{
1204 GncPluginPageReportPrivate *priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(plugin_page);
1205 priv->action_group = NULL;
1206}
1207
1208static GObject*
1209gnc_plugin_page_report_constructor(GType this_type, guint n_properties, GObjectConstructParam *properties)
1210{
1211 GObject *obj = G_OBJECT_CLASS (gnc_plugin_page_report_parent_class)->constructor(this_type, n_properties, properties);
1212
1213 gint reportId = -42;
1214 for (decltype(n_properties) i = 0; i < n_properties; i++)
1215 {
1216 GObjectConstructParam prop = properties[i];
1217 if (strcmp(prop.pspec->name, "report-id") == 0)
1218 {
1219 reportId = g_value_get_int(prop.value);
1220 }
1221 }
1222
1223 gnc_plugin_page_report_constr_init(GNC_PLUGIN_PAGE_REPORT(obj), reportId);
1224
1225 return obj;
1226}
1227
1228static void
1229gnc_plugin_page_report_menu_update (GncPluginPage *plugin_page,
1230 action_toolbar_labels *tooltip_list)
1231{
1232 GncMainWindow *window = GNC_MAIN_WINDOW(GNC_PLUGIN_PAGE(plugin_page)->window);
1233 GtkWidget *tool_item;
1234
1235 for (gint i = 0; (tooltip_list[i].action_name != nullptr); i++)
1236 {
1238 tooltip_list[i].action_name,
1239 _(tooltip_list[i].label),
1240 _(tooltip_list[i].tooltip));
1241
1242 tool_item = gnc_main_window_toolbar_find_tool_item (window,
1243 tooltip_list[i].action_name);
1244 if (tool_item)
1245 { // only need to update the tooltip here
1246 gtk_widget_set_tooltip_text (GTK_WIDGET(tool_item), _(tooltip_list[i].tooltip));
1247 g_object_set (G_OBJECT(tool_item), "has-tooltip", false, nullptr);
1248 }
1249 }
1250 // need to add the accelerator keys for the updated menu items
1252}
1253
1254static void
1255gnc_plugin_page_report_menu_updates (GncPluginPage *plugin_page)
1256{
1258 GncPluginPageReport *report;
1259 GncMainWindow *window;
1260 action_toolbar_labels tooltip_list[3];
1261 GAction *action;
1262
1263 gchar *saved_reports_path = gnc_build_userdata_path (SAVED_REPORTS_FILE);
1264 gchar *report_save_str = g_strdup_printf (
1265 _("Update the current report's saved configuration. "
1266 "The report configuration will be saved in the file %s."), saved_reports_path);
1267 gchar *report_saveas_str = g_strdup_printf (
1268 _("Add the current report's configuration to the 'Reports->Saved Report Configurations' menu. "
1269 "The report configuration will be saved in the file %s."), saved_reports_path);
1270
1271 report = GNC_PLUGIN_PAGE_REPORT(plugin_page);
1272 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1273
1274 window = (GncMainWindow*)gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(plugin_page));
1275
1276 tooltip_list[0] = { "ReportSaveAction", N_("Save _Report Configuration"), report_save_str };
1277 tooltip_list[1] = { "ReportSaveAsAction", N_("Save Report Configuration As…"), report_saveas_str };
1278 tooltip_list[2] = { nullptr, nullptr, nullptr };
1279
1280 gnc_plugin_page_report_menu_update (plugin_page, tooltip_list);
1281
1282 /* Enable the FilePrintAction */
1283 action = gnc_main_window_find_action (window, "FilePrintAction");
1284 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), true);
1285
1286 if (priv->webkit2)
1287 {
1288 GtkWidget *pdf_item = gnc_main_window_menu_find_menu_item (window, "FilePrintPDFAction");
1289 gtk_widget_hide (pdf_item);
1290 }
1291 g_free (saved_reports_path);
1292 g_free (report_save_str);
1293 g_free (report_saveas_str);
1294}
1295
1296static void
1297gnc_plugin_page_report_constr_init (GncPluginPageReport *plugin_page, gint reportId)
1298{
1300 GncPluginPage *parent;
1301 gboolean use_new;
1302 gchar *name;
1303
1304 DEBUG("property reportId=%d", reportId);
1305 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(plugin_page);
1306 priv->reportId = reportId;
1307 priv->webkit2 = FALSE;
1308
1309 gnc_plugin_page_report_setup( GNC_PLUGIN_PAGE(plugin_page));
1310
1311 /* Init parent declared variables */
1312 parent = GNC_PLUGIN_PAGE(plugin_page);
1313 use_new = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REPORT, GNC_PREF_USE_NEW);
1314 name = gnc_report_name (priv->initial_report);
1315 g_object_set (G_OBJECT(plugin_page),
1316 "page-name", name,
1317 "ui-description", "gnc-plugin-page-report.ui",
1318 "use-new-window", use_new,
1319 nullptr);
1320 g_free (name);
1321
1322 /* change me when the system supports multiple books */
1323 gnc_plugin_page_add_book (parent, gnc_get_current_book());
1324
1325 /* Create menu and toolbar information */
1326 priv->action_group = gnc_plugin_page_create_action_group (parent, "GncPluginPageReportActions");
1327 g_action_map_add_action_entries (G_ACTION_MAP(priv->action_group),
1328 report_actions,
1329 num_report_actions,
1330 plugin_page);
1331
1332 gnc_plugin_set_actions_enabled (G_ACTION_MAP(priv->action_group), initially_insensitive_actions,
1333 FALSE);
1334 gnc_plugin_set_actions_enabled(G_ACTION_MAP(priv->action_group),
1335 disable_during_load_actions, FALSE);
1336}
1337
1339gnc_plugin_page_report_new( int reportId )
1340{
1341 DEBUG( "report id = %d", reportId );
1342 auto plugin_page{g_object_new(GNC_TYPE_PLUGIN_PAGE_REPORT, "report-id",
1343 reportId, nullptr)};
1344 DEBUG( "plugin_page: %p", plugin_page );
1345 DEBUG( "set %d on page %p", reportId, plugin_page );
1346 return GNC_PLUGIN_PAGE( plugin_page );
1347}
1348
1349void
1350gnc_plugin_page_report_remove_edited_report(GncPluginPageReportPrivate *priv,
1351 SCM report)
1352{
1353 SCM new_edited = scm_delete(priv->edited_reports, report);
1354 if (priv->edited_reports != SCM_EOL)
1355 scm_gc_unprotect_object(priv->edited_reports);
1356 priv->edited_reports = new_edited;
1357 if (new_edited != SCM_EOL)
1358 scm_gc_protect_object(priv->edited_reports);
1359}
1360
1361void
1362gnc_plugin_page_report_add_edited_report(GncPluginPageReportPrivate *priv,
1363 SCM report)
1364{
1365 SCM new_edited = scm_cons(report, priv->edited_reports);
1366 if (priv->edited_reports != SCM_EOL)
1367 scm_gc_unprotect_object(priv->edited_reports);
1368 priv->edited_reports = new_edited;
1369 if (new_edited != SCM_EOL)
1370 scm_gc_protect_object(priv->edited_reports);
1371}
1372
1373void
1374gnc_plugin_page_report_raise_editor(SCM report)
1375{
1376 SCM get_editor = scm_c_eval_string("gnc:report-editor-widget");
1377 SCM editor = scm_call_1(get_editor, report);
1378#define FUNC_NAME "gtk_window_present"
1379 auto w{static_cast<GtkWidget *>(SWIG_MustGetPtr(editor, SWIG_TypeQuery("_p_GtkWidget"), 1, 0))};
1380#undef FUNC_NAME
1381 gtk_window_present(GTK_WINDOW(w));
1382}
1383
1384static void
1385close_handler (gpointer user_data)
1386{
1387 GncPluginPage *plugin_page = GNC_PLUGIN_PAGE(user_data);
1388 DEBUG("in close handler\n");
1389 gnc_main_window_close_page (plugin_page);
1390}
1391
1392static void
1393gnc_plugin_page_report_set_fwd_button (GncPluginPageReport *report, int enabled)
1394{
1395 GAction *action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(report),
1396 "ReportForwAction");
1397 if (action != NULL)
1398 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), enabled);
1399}
1400
1401static void
1402gnc_plugin_page_report_set_back_button (GncPluginPageReport *report, int enabled)
1403{
1404 GAction *action = gnc_plugin_page_get_action (GNC_PLUGIN_PAGE(report),
1405 "ReportBackAction");
1406 if (action != NULL)
1407 g_simple_action_set_enabled (G_SIMPLE_ACTION(action), enabled);
1408}
1409
1410// ------------------------------------------------------------
1411// GTK ACTION CALLBACKS
1412
1413static void
1414gnc_plugin_page_report_forw_cb (GSimpleAction *simple,
1415 GVariant *parameter,
1416 gpointer user_data)
1417{
1418 GncPluginPageReport *report = (GncPluginPageReport*)user_data;
1420 gnc_html_history_node * node = nullptr;
1421
1422 DEBUG( "forw" );
1423 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1424 gnc_html_history_forward(gnc_html_get_history(priv->html));
1425 node = gnc_html_history_get_current(gnc_html_get_history(priv->html));
1426 if (node)
1427 {
1428 gnc_html_show_url(priv->html, node->type, node->location,
1429 node->label, 0);
1430 }
1431}
1432
1433static void
1434gnc_plugin_page_report_back_cb (GSimpleAction *simple,
1435 GVariant *parameter,
1436 gpointer user_data)
1437{
1438 GncPluginPageReport *report = (GncPluginPageReport*)user_data;
1440 gnc_html_history_node * node;
1441
1442 DEBUG( "back" );
1443 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1444 gnc_html_history_back(gnc_html_get_history(priv->html));
1445 node = gnc_html_history_get_current(gnc_html_get_history(priv->html));
1446 if (node)
1447 {
1448 gnc_html_show_url(priv->html, node->type, node->location,
1449 node->label, 0);
1450 }
1451}
1452
1453void
1454gnc_plugin_page_report_reload (GncPluginPageReport *report)
1455{
1456 gnc_plugin_page_report_reload_cb (nullptr, nullptr, report);
1457}
1458
1459static void
1460gnc_plugin_page_report_reload_cb (GSimpleAction *simple,
1461 GVariant *parameter,
1462 gpointer user_data)
1463{
1464 GncPluginPageReport *report = (GncPluginPageReport*)user_data;
1465 GncPluginPage *page;
1467 SCM dirty_report;
1468
1469 DEBUG( "reload" );
1470 page = GNC_PLUGIN_PAGE(report);
1471 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1472 if (priv->cur_report == SCM_BOOL_F)
1473 return;
1474
1475 DEBUG( "reload-redraw" );
1476 dirty_report = scm_c_eval_string("gnc:report-set-dirty?!");
1477 scm_call_2(dirty_report, priv->cur_report, SCM_BOOL_T);
1478
1479 /* now queue the fact that we need to reload this report */
1480 // Disable some actions reported to crash while loading
1481 gnc_plugin_set_actions_enabled(G_ACTION_MAP(priv->action_group),
1482 disable_during_load_actions, FALSE);
1483 // prevent closing this page while loading...
1484 priv->reloading = TRUE;
1485 // this sets the window for the progressbar
1486 gnc_window_set_progressbar_window( GNC_WINDOW(page->window) );
1487
1488 // this sets the minimum size of the progressbar to that allocated
1489 gnc_plugin_page_report_set_progressbar( page, TRUE );
1490
1491 gnc_html_reload( priv->html, TRUE ); //reload by rebuild
1492
1493 gnc_plugin_page_report_set_progressbar( page, FALSE );
1494
1495 // this resets the window for the progressbar to nullptr
1496 gnc_window_set_progressbar_window( nullptr );
1497 gnc_plugin_set_actions_enabled(G_ACTION_MAP(priv->action_group),
1498 disable_during_load_actions, TRUE);
1499 priv->reloading = FALSE;
1500}
1501
1502static void
1503gnc_plugin_page_report_stop_cb (GSimpleAction *simple,
1504 GVariant *parameter,
1505 gpointer user_data)
1506{
1507 GncPluginPageReport *report = (GncPluginPageReport*)user_data;
1509
1510 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1511 gnc_html_cancel(priv->html);
1512}
1513
1514/* Returns SCM_BOOL_F if cancel. Returns SCM_BOOL_T if html.
1515 * Otherwise returns pair from export_types. */
1516static SCM
1517gnc_get_export_type_choice (SCM export_types, GtkWindow *parent)
1518{
1519 GList * choices = nullptr;
1520 gboolean bad = FALSE;
1521 GList * node;
1522 int choice;
1523 SCM tail;
1524
1525 if (!scm_is_list (export_types))
1526 return SCM_BOOL_F;
1527
1528 for (tail = export_types; !scm_is_null (tail); tail = SCM_CDR (tail))
1529 {
1530 SCM pair = SCM_CAR (tail);
1531 char * name;
1532 SCM scm;
1533
1534 if (!scm_is_pair (pair))
1535 {
1536 g_warning ("unexpected list element");
1537 bad = TRUE;
1538 break;
1539 }
1540
1541 scm = SCM_CAR (pair);
1542 if (!scm_is_string (scm))
1543 {
1544 g_warning ("unexpected pair element");
1545 bad = TRUE;
1546 break;
1547 }
1548
1549 name = gnc_scm_to_utf8_string (scm);
1550 choices = g_list_prepend (choices, name);
1551 }
1552
1553 if (!bad)
1554 {
1555 choices = g_list_reverse (choices);
1556
1557 choices = g_list_prepend (choices, g_strdup (_("HTML")));
1558
1559 choice = gnc_choose_radio_option_dialog
1560 (GTK_WIDGET (parent), _("Choose export format"),
1561 _("Choose the export format for this report:"),
1562 nullptr, 0, choices);
1563 }
1564 else
1565 choice = -1;
1566
1567 for (node = choices; node; node = node->next)
1568 g_free (node->data);
1569 g_list_free (choices);
1570
1571 if (choice < 0)
1572 return SCM_BOOL_F;
1573
1574 if (choice == 0)
1575 return SCM_BOOL_T;
1576
1577 choice--;
1578 if (choice >= scm_ilength (export_types))
1579 return SCM_BOOL_F;
1580
1581 return scm_list_ref (export_types, scm_from_int (choice));
1582}
1583
1584static char *
1585gnc_get_export_filename (SCM choice, GtkWindow *parent)
1586{
1587 char * filepath;
1588 GStatBuf statbuf;
1589 char * title;
1590 const gchar * html_type = _("HTML");
1591 char * type;
1592 int rc;
1593 char * default_dir;
1594
1595 if (choice == SCM_BOOL_T)
1596 type = g_strdup (html_type);
1597 else
1598 type = gnc_scm_to_utf8_string(SCM_CAR (choice));
1599
1600 /* %s is the type of what is about to be saved, e.g. "HTML". */
1601 title = g_strdup_printf (_("Save %s To File"), type);
1602 default_dir = gnc_get_default_directory(GNC_PREFS_GROUP_REPORT);
1603
1604 filepath = gnc_file_dialog (parent, title, nullptr, default_dir,
1605 GNC_FILE_DIALOG_EXPORT);
1606
1607 /* Try to test for extension on file name, add if missing */
1608 if (filepath && strchr (filepath, '.') == nullptr)
1609 {
1610 char* extension = g_ascii_strdown (type, -1);
1611 char* newpath = g_strdup_printf ("%s.%s", filepath, extension);
1612 g_free (extension);
1613 g_free (filepath);
1614 filepath = newpath;
1615 }
1616
1617 g_free (type);
1618 g_free (title);
1619 g_free (default_dir);
1620
1621 if (!filepath)
1622 return nullptr;
1623
1624 default_dir = g_path_get_dirname(filepath);
1625 gnc_set_default_directory (GNC_PREFS_GROUP_REPORT, default_dir);
1626 g_free(default_dir);
1627
1628 rc = g_stat (filepath, &statbuf);
1629
1630 /* Check for an error that isn't a non-existent file. */
1631 if (rc != 0 && errno != ENOENT)
1632 {
1633 /* %s is the strerror(3) string of the error that occurred. */
1634 const char *format = _("You cannot save to that filename.\n\n%s");
1635
1636 gnc_error_dialog (parent, format, strerror(errno));
1637 g_free(filepath);
1638 return nullptr;
1639 }
1640
1641 /* Check for a file that isn't a regular file. */
1642 if (rc == 0 && !S_ISREG (statbuf.st_mode))
1643 {
1644 const char *message = _("You cannot save to that file.");
1645
1646 gnc_error_dialog (parent, "%s", message);
1647 g_free(filepath);
1648 return nullptr;
1649 }
1650
1651 if (rc == 0)
1652 {
1653 const char *format = _("The file %s already exists. "
1654 "Are you sure you want to overwrite it?");
1655
1656 if (!gnc_verify_dialog (parent, FALSE, format, filepath))
1657 {
1658 g_free(filepath);
1659 return nullptr;
1660 }
1661 }
1662
1663 return filepath;
1664}
1665
1666static void
1667gnc_plugin_page_report_edit_tax_cb (GSimpleAction *simple,
1668 GVariant *parameter,
1669 gpointer user_data)
1670{
1671 GncPluginPageReport *report = (GncPluginPageReport*)user_data;
1672 GtkWidget *window;
1673
1674 window = GNC_PLUGIN_PAGE(report)->window;
1675 gnc_tax_info_dialog (window, nullptr);
1676}
1677
1678static void
1679gnc_plugin_page_report_save_as_cb (GSimpleAction *simple,
1680 GVariant *parameter,
1681 gpointer user_data)
1682{
1683 GncPluginPageReport *report = (GncPluginPageReport*)user_data;
1685 SCM save_func;
1686 SCM rpt_id;
1687
1688 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1689 if (priv->cur_report == SCM_BOOL_F)
1690 return;
1691
1692 /* Create a new report template based on the current report's settings
1693 * and allow the user to rename the template.
1694 */
1695 save_func = scm_c_eval_string("gnc:report-to-template-new");
1696 rpt_id = scm_call_1(save_func, priv->cur_report);
1697
1698 /* Open Preconfigured Reports dialog to allow user to change the name */
1699 if (!scm_is_null (rpt_id))
1700 {
1701 GncPluginPage *reportPage = GNC_PLUGIN_PAGE (report);
1702 GtkWidget *window = reportPage->window;
1703
1704 if (window)
1705 g_return_if_fail(GNC_IS_MAIN_WINDOW(window));
1706
1707 gnc_ui_custom_report_edit_name (GNC_MAIN_WINDOW (window), rpt_id);
1708 }
1709
1710}
1711
1712static void
1713gnc_plugin_page_report_save_cb (GSimpleAction *simple,
1714 GVariant *parameter,
1715 gpointer user_data)
1716{
1717 GncPluginPageReport *report = (GncPluginPageReport*)user_data;
1719 SCM check_func, save_func;
1720 SCM rpt_id;
1721
1722 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1723 if (priv->cur_report == SCM_BOOL_F)
1724 return;
1725
1726 check_func = scm_c_eval_string("gnc:is-custom-report-type");
1727 if (scm_is_true (scm_call_1 (check_func, priv->cur_report)))
1728 {
1729 auto report_name_str{priv->cur_odb->lookup_string_option("General", "Report name")};
1730 auto window{GTK_WINDOW(gnc_plugin_page_get_window (GNC_PLUGIN_PAGE(report)))};
1731
1732 if (!gnc_action_dialog (window, _("_Overwrite"), false, _("This will update and \
1733overwrite the existing saved report named \"%s\"."), report_name_str.c_str()))
1734 return;
1735
1736 /* The current report is already based on a custom report.
1737 * Replace the existing one instead of adding a new one
1738 */
1739 save_func = scm_c_eval_string("gnc:report-to-template-update");
1740 rpt_id = scm_call_1(save_func, priv->cur_report);
1741 (void)rpt_id;
1742 }
1743 else
1744 {
1745 /* The current report is not based on a custom report.
1746 * So let's create a new report template based on this report
1747 * and allow the user to change the name.
1748 */
1749 gnc_plugin_page_report_save_as_cb (simple, parameter, report);
1750 }
1751}
1752
1753static void
1754gnc_plugin_page_report_export_cb (GSimpleAction *simple,
1755 GVariant *parameter,
1756 gpointer user_data)
1757{
1758 GncPluginPageReport *report = (GncPluginPageReport*)user_data;
1760 char * filepath;
1761 SCM export_types;
1762 SCM export_thunk;
1763 gboolean result;
1764 SCM choice;
1765 GtkWindow *parent = GTK_WINDOW (gnc_plugin_page_get_window
1766 (GNC_PLUGIN_PAGE (report)));
1767
1768 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1769 export_types = scm_call_1 (scm_c_eval_string ("gnc:report-export-types"),
1770 priv->cur_report);
1771
1772 export_thunk = scm_call_1 (scm_c_eval_string ("gnc:report-export-thunk"),
1773 priv->cur_report);
1774
1775 if (scm_is_list (export_types) && scm_is_procedure (export_thunk))
1776 choice = gnc_get_export_type_choice (export_types, parent);
1777 else
1778 choice = SCM_BOOL_T;
1779
1780 if (choice == SCM_BOOL_F)
1781 return;
1782
1783 filepath = gnc_get_export_filename (choice, parent);
1784 if (!filepath)
1785 return;
1786
1787 if (scm_is_pair (choice))
1788 {
1789 SCM type = scm_cdr (choice);
1790 SCM document = scm_call_2 (export_thunk, priv->cur_report, type);
1791 SCM query_result = scm_c_eval_string ("gnc:html-document?");
1792 SCM get_export_string = scm_c_eval_string ("gnc:html-document-export-string");
1793 SCM get_export_error = scm_c_eval_string ("gnc:html-document-export-error");
1794
1795 if (scm_is_false (scm_call_1 (query_result, document)))
1796 gnc_error_dialog (parent, "%s",
1797 _("This report must be upgraded to return a "
1798 "document object with export-string or "
1799 "export-error."));
1800 else
1801 {
1802 SCM export_string = scm_call_1 (get_export_string, document);
1803 SCM export_error = scm_call_1 (get_export_error, document);
1804
1805 if (scm_is_string (export_string))
1806 {
1807 GError *err = nullptr;
1808 gchar *exported = scm_to_utf8_string (export_string);
1809 if (!g_file_set_contents (filepath, exported, -1, &err))
1810 gnc_error_dialog (parent, "Error during export: %s", err->message);
1811 g_free (exported);
1812 if (err)
1813 g_error_free (err);
1814 }
1815 else if (scm_is_string (export_error))
1816 {
1817 gchar *str = scm_to_utf8_string (export_error);
1818 gnc_error_dialog (parent, "error during export: %s", str);
1819 g_free (str);
1820 }
1821 else
1822 gnc_error_dialog (parent, "%s",
1823 _("This report must be upgraded to return a "
1824 "document object with export-string or "
1825 "export-error."));
1826 }
1827 result = TRUE;
1828 }
1829 else
1830 result = gnc_html_export_to_file (priv->html, filepath);
1831
1832 if (!result)
1833 {
1834 const char *fmt = _("Could not open the file %s. "
1835 "The error is: %s");
1836 gnc_error_dialog (parent, fmt, filepath ? filepath : "(null)",
1837 strerror (errno) ? strerror (errno) : "" );
1838 }
1839
1840 g_free(filepath);
1841 return;
1842}
1843
1844static void
1845gnc_plugin_page_report_options_cb (GSimpleAction *simple,
1846 GVariant *parameter,
1847 gpointer user_data)
1848{
1849 GncPluginPageReport *report = (GncPluginPageReport*)user_data;
1851 GtkWindow *parent = GTK_WINDOW (gnc_plugin_page_get_window (GNC_PLUGIN_PAGE (report)));
1852 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
1853 if (priv->cur_report == SCM_BOOL_F)
1854 return;
1855
1856 if (gnc_report_edit_options (priv->cur_report, parent))
1857 gnc_plugin_page_report_add_edited_report(priv, priv->cur_report);
1858}
1859
1860static GncInvoice*
1861lookup_invoice(GncPluginPageReportPrivate *priv)
1862{
1863 const QofInstance* opt_val =
1865 "Invoice Number");
1866 return GNC_INVOICE(opt_val);
1867}
1868
1869#define GNC_PREFS_GROUP_REPORT_PDFEXPORT GNC_PREFS_GROUP_GENERAL_REPORT ".pdf-export"
1870#define GNC_PREF_FILENAME_DATE_FMT "filename-date-format"
1871#define GNC_PREF_FILENAME_FMT "filename-format"
1872
1873static gchar *report_create_jobname(GncPluginPageReportPrivate *priv)
1874{
1875 gchar *job_name = nullptr;
1876 gchar *report_name = nullptr;
1877 const gchar *report_number = "";
1878 gchar *job_date;
1879 const gchar *default_jobname = N_("GnuCash-Report");
1880
1881 g_assert(priv);
1882
1883 {
1884 // Look up the date format that was chosen in the preferences database
1885 QofDateFormat date_format_here = QOF_DATE_FORMAT_ISO;
1886 char *format_code = gnc_prefs_get_string (GNC_PREFS_GROUP_REPORT_PDFEXPORT,
1887 GNC_PREF_FILENAME_DATE_FMT);
1888 const gchar *date_format_string;
1889 if (!(format_code && *format_code))
1890 {
1891 g_free(format_code);
1892 format_code = g_strdup("locale");
1893 }
1894
1895 if (gnc_date_string_to_dateformat (format_code, &date_format_here))
1896 PERR("Incorrect date format code, using ISO-8601.");
1897
1898 date_format_string = qof_date_format_get_string (date_format_here);
1899
1900 job_date = gnc_print_time64 (gnc_time (nullptr), date_format_string);
1901 g_free (format_code);
1902 }
1903
1904
1905 if (priv->cur_report == SCM_BOOL_F)
1906 report_name = g_strdup (_(default_jobname));
1907 else
1908 {
1909 /* Gather some information from the report to generate a
1910 * decent print job name.
1911 * FIXME: this is a bit of a hack. It would be better if each
1912 * report had a hidden job name option, because the
1913 * generic reporting code shouldn't know what makes
1914 * a decent job name for each report.
1915 *
1916 * Also, the "Report name" for an invoice report is
1917 * "Printable Invoice", which is not what the user wants to see,
1918 * so I added yet another hack below for this. cstim.
1919 */
1920 GncInvoice *invoice;
1921 auto report_name_str = priv->cur_odb->lookup_string_option("General",
1922 "Report name");
1923 if (!report_name_str.empty())
1924 report_name = g_strdup(report_name_str.c_str());
1925 else
1926 report_name = g_strdup (_(default_jobname));
1927
1928 if (g_strcmp0(report_name, _("Printable Invoice")) == 0
1929 || g_strcmp0(report_name, _("Tax Invoice")) == 0
1930 || g_strcmp0(report_name, _("Easy Invoice")) == 0
1931 || g_strcmp0(report_name, _("Fancy Invoice")) == 0)
1932 {
1933 /* Again HACK alert: We modify this single known string here into
1934 * something more appropriate. */
1935 g_free(report_name);
1936 report_name = g_strdup(_("Invoice"));
1937 }
1938
1939 invoice = lookup_invoice(priv);
1940 if (invoice)
1941 {
1942 // Report is for an invoice. Hence, we get a number of the invoice.
1943 report_number = gncInvoiceGetID(invoice);
1944 }
1945 }
1946
1947 if (report_name && job_date)
1948 {
1949 // Look up the printf format of the output name from the preferences database
1950 char* format = gnc_prefs_get_string(GNC_PREFS_GROUP_REPORT_PDFEXPORT, GNC_PREF_FILENAME_FMT);
1951
1952 if (format && *format)
1953 {
1954 job_name = g_strdup_printf(format, report_name,
1955 report_number, job_date);
1956 }
1957 else
1958 {
1959 PWARN("No GNC_PREF_FILENAME_FMT!");
1960 job_name = g_strdup_printf ("%s %s %s", report_name,
1961 report_number, job_date);
1962 }
1963 g_free(format);
1964 }
1965 g_free (report_name);
1966 g_free (job_date);
1967
1968 {
1969 char forbidden_char = '/';
1970 // Now remove the characters that are not allowed in file
1971 // names. FIXME: Check for all disallowed characters here!
1972 while (strchr(job_name, forbidden_char))
1973 {
1974 *strchr(job_name, forbidden_char) = '_';
1975 }
1976 }
1977
1978 {
1979 /* And one final checking issue: We want to avoid allocating
1980 * the same name twice for a saved PDF. Hence, we keep a
1981 * unordered_map with the usage count of existing output
1982 * names. */
1983
1984 auto& value = static_report_printnames[job_name];
1985 value++;
1986
1987 if (value > 1)
1988 {
1989 // The name was already in use, so modify the name again
1990 gchar *tmp = g_strdup_printf("%s_%d", job_name, value);
1991 g_free(job_name);
1992 job_name = tmp;
1993 }
1994 }
1995
1996 return job_name;
1997}
1998
1999static void
2000gnc_plugin_page_report_print_cb (GSimpleAction *simple,
2001 GVariant *parameter,
2002 gpointer user_data)
2003{
2004 GncPluginPageReport *report = (GncPluginPageReport*)user_data;
2005 GncPluginPageReportPrivate *priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
2006 gchar *job_name = report_create_jobname(priv);
2007
2008 //g_warning("Setting job name=%s", job_name);
2009
2010#ifdef WEBKIT1
2011 gnc_html_print (priv->html, job_name, FALSE);
2012#else
2013 gnc_html_print (priv->html, job_name);
2014#endif
2015
2016 g_free (job_name);
2017}
2018
2019static void
2020gnc_plugin_page_report_exportpdf_cb (GSimpleAction *simple,
2021 GVariant *parameter,
2022 gpointer user_data)
2023{
2024 GncPluginPageReport *report = (GncPluginPageReport*)user_data;
2025 GncPluginPageReportPrivate *priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
2026 gchar *job_name = report_create_jobname(priv);
2027 GncInvoice *invoice;
2028 GncOwner *owner = nullptr;
2029
2030 // Do we have an invoice report?
2031 invoice = lookup_invoice(priv);
2032 if (invoice)
2033 {
2034 // Does this invoice also have an owner?
2035 owner = (GncOwner*) gncInvoiceGetOwner(invoice);
2036 if (owner)
2037 {
2038 QofInstance *inst = qofOwnerGetOwner (owner);
2039 gchar *dirname = nullptr;
2040 qof_instance_get (inst, "export-pdf-dir", &dirname, nullptr);
2041 // Yes. In the kvp, look up the key for the Export-PDF output
2042 // directory. If it exists, prepend this to the job name so that
2043 // we can export to PDF.
2044 if (dirname && g_file_test (dirname,
2045 (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
2046 {
2047 gchar *tmp = g_build_filename (dirname, job_name, nullptr);
2048 g_free (job_name);
2049 job_name = tmp;
2050 }
2051 }
2052 }
2053
2054 //g_warning("Setting job name=%s", job_name);
2055
2056#ifdef WEBKIT1
2057 gnc_html_print (priv->html, job_name, TRUE);
2058#else
2059 gnc_html_print (priv->html, job_name);
2060#endif
2061
2062 if (owner)
2063 {
2064 /* As this is an invoice report with some owner, we will try
2065 * to look up the chosen output directory from the print
2066 * settings and store it again in the owner kvp.
2067 */
2068 GtkPrintSettings *print_settings = gnc_print_get_settings();
2069 if (print_settings && gtk_print_settings_has_key (print_settings,
2071 {
2072 const char* dirname = gtk_print_settings_get (print_settings,
2074 // Only store the directory if it exists.
2075 if (g_file_test (dirname,
2076 (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
2077 {
2078 QofInstance *inst = qofOwnerGetOwner (owner);
2079 gncOwnerBeginEdit (owner);
2080 qof_instance_set (inst, "export-pdf-dir", dirname);
2081 gncOwnerCommitEdit (owner);
2082 }
2083 }
2084 }
2085 g_free (job_name);
2086}
2087
2088static void
2089gnc_plugin_page_report_copy_cb (GSimpleAction *simple,
2090 GVariant *parameter,
2091 gpointer user_data)
2092{
2093 GncPluginPageReport *report = (GncPluginPageReport*)user_data;
2095
2096 priv = GNC_PLUGIN_PAGE_REPORT_GET_PRIVATE(report);
2097 gnc_html_copy_to_clipboard(priv->html);
2098}
2099
2100/********************************************************************
2101 * gnc_main_window_open_report()
2102 * open an report in a top level window from an ID number
2103 ********************************************************************/
2104
2105void
2106gnc_main_window_open_report(int report_id, GncMainWindow *window)
2107{
2108 GncPluginPage *reportPage;
2109
2110 if (window)
2111 g_return_if_fail(GNC_IS_MAIN_WINDOW(window));
2112
2113 reportPage = gnc_plugin_page_report_new( report_id );
2114 gnc_main_window_open_page( window, reportPage );
2115}
2116
2117void
2118gnc_main_window_open_report_url(const char * url, GncMainWindow *window)
2119{
2120 GncPluginPage *reportPage;
2121
2122 DEBUG( "report url: [%s]\n", url );
2123
2124 if (window)
2125 g_return_if_fail(GNC_IS_MAIN_WINDOW(window));
2126
2127 reportPage = gnc_plugin_page_report_new( 42 /* url? */ );
2128 gnc_main_window_open_page( window, reportPage );
2129}
2130
GtkPrintSettings * gnc_print_get_settings()
Returns the pointer to our static GtkPrintSettings object.
#define GNC_GTK_PRINT_SETTINGS_EXPORT_DIR
Key for saving the PDF-export directory in the print settings.
GSimpleActionGroup * gnc_plugin_page_create_action_group(GncPluginPage *page, const gchar *group_name)
Create the GSimpleActionGroup object associated with this page.
GtkWidget * gnc_plugin_page_get_window(GncPluginPage *page)
Retrieve a pointer to the GncMainWindow (GtkWindow) containing this page.
void gnc_plugin_page_disconnect_page_changed(GncPluginPage *page)
Disconnect the page_changed_id signal callback.
GAction * gnc_plugin_page_get_action(GncPluginPage *page, const gchar *name)
Retrieve a GAction object associated with this page.
void gnc_plugin_page_add_book(GncPluginPage *page, QofBook *book)
Add a book reference to the specified page.
const gchar * gnc_plugin_page_get_page_name(GncPluginPage *page)
Retrieve the name of this page.
void gnc_plugin_page_inserted_cb(GncPluginPage *page, gpointer user_data)
Set up the page_changed callback for when the current page is changed.
QofDateFormat
Enum for determining a date format.
Definition gnc-date.h:123
char * gnc_print_time64(time64 time, const char *format)
print a time64 as a date string per format
Definition gnc-date.cpp:370
time64 gnc_time(time64 *tbuf)
get the current time
Definition gnc-date.cpp:262
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:502
@ QOF_DATE_FORMAT_ISO
ISO: yyyy-mm-dd.
Definition gnc-date.h:127
void gnc_main_window_menu_add_accelerator_keys(GncMainWindow *window)
Scan the main window menu and add accelerator keys to main window accelerator group.
gboolean gnc_main_window_is_restoring_pages(GncMainWindow *window)
Check if the main window is restoring the plugin pages.
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.
GAction * gnc_main_window_find_action(GncMainWindow *window, const gchar *action_name)
Find the GAction in the main window.
void gnc_main_window_init_short_names(GncMainWindow *window, GncToolBarShortNames *toolbar_labels)
Update the labels of the toolbar items with short names.
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
void main_window_update_page_name(GncPluginPage *page, const gchar *name_in)
Update the name of the page in the main window.
void gnc_main_window_open_page(GncMainWindow *window, GncPluginPage *page)
Display a data plugin page in a window.
gboolean gnc_main_window_update_menu_for_action(GncMainWindow *window, const gchar *action_name, const gchar *label, const gchar *tooltip)
Find the GMenuModel item given the action name for the window specified.
GtkWidget * gnc_main_window_menu_find_menu_item(GncMainWindow *window, const gchar *action_name)
Find the menu item with the given action name for the window specified.
void gnc_main_window_update_menu_and_toolbar(GncMainWindow *window, GncPluginPage *page, const gchar **ui_updates)
Update the main window menu with the placeholders listed in ui_updates and load the page specific too...
GtkWidget * gnc_main_window_toolbar_find_tool_item(GncMainWindow *window, const gchar *action_name)
Find the toolbar item with the given action name for the window specified.
void gnc_main_window_close_page(GncPluginPage *page)
Remove a data plugin page from a window and display the previous page.
GncPluginPage * gnc_plugin_page_report_new(int reportId)
#define SCHEME_OPTIONS
The key name used it the state file for storing the report options.
void gnc_utf8_strip_invalid_and_controls(gchar *str)
Strip any non-utf8 characters and any control characters (everything < 0x20, , \f,...
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.
void qof_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
#define PINFO(format, args...)
Print an informational note.
Definition qoflog.h:256
#define DEBUG(format, args...)
Print a debugging message.
Definition qoflog.h:264
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define PERR(format, args...)
Log a serious error.
Definition qoflog.h:244
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
void gnc_plugin_set_actions_enabled(GActionMap *action_map, const gchar **action_names, gboolean enable)
This function sets the sensitivity of a GAction in a specific group.
Definition gnc-plugin.c:250
const QofInstance * gnc_option_db_lookup_qofinstance_value(GncOptionDB *odb, const char *section, const char *name)
Retrieve the QofInstance value of an option in the GncOptionDB.
void gnc_option_db_destroy(GncOptionDB *odb)
Destruct and release a GncOptionDB.
void gncOwnerBeginEdit(GncOwner *owner)
These are convenience wrappers around gnc{Vendor,Customer,Job,Employee}* functions.
Definition gncOwner.c:72
QofInstance * qofOwnerGetOwner(const GncOwner *owner)
return the owner itself as an entity.
Definition gncOwner.c:275
gchar * gnc_prefs_get_string(const gchar *group, const gchar *pref_name)
Get a string value from the preferences backend.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
The class data structure for a content plugin.
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(* 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...
const gchar * tab_icon
The relative name of the icon that should be shown on the tab for this page.
const gchar * plugin_name
The textual name of this plugin.
void(* destroy_widget)(GncPluginPage *plugin_page)
Function called to destroy the display widget for a particular type of plugin.
gboolean(* finish_pending)(GncPluginPage *plugin_page)
This function vector is called to finish any outstanding activities.
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.
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.
GtkWidget *(* create_widget)(GncPluginPage *plugin_page)
Function called to create the display widget for a particular type of plugin.
gboolean(* focus_page_function)(GncPluginPage *plugin_page)
This function performs specific actions to set the focus on a specific widget.
GncOptionDB * cur_odb
The Option DB for this report.
GtkContainer * container
the container the above HTML widget is in.
SCM cur_report
The report which this Page is satisfying.
GncHtml * html
the gnc_html abstraction this PluginPage contains
The instance data structure for a content plugin.
GtkWidget * window
The window that contains the display widget for this plugin.
A structure for defining alternate action names for use in the toolbar.
A structure for defining alternate action names for use in the toolbar.
Definition gnc-plugin.h:205
const char * action_name
The name of the action.
Definition gnc-plugin.h:207

◆ GNC_PLUGIN_PAGE_REPORT_NAME

#define GNC_PLUGIN_PAGE_REPORT_NAME   "GncPluginPageReport"

Definition at line 53 of file gnc-plugin-page-report.h.

◆ GNC_PREF_FILENAME_DATE_FMT

#define GNC_PREF_FILENAME_DATE_FMT   "filename-date-format"

Definition at line 1871 of file gnc-plugin-page-report.cpp.

◆ GNC_PREF_FILENAME_FMT

#define GNC_PREF_FILENAME_FMT   "filename-format"

Definition at line 1872 of file gnc-plugin-page-report.cpp.

◆ GNC_PREFS_GROUP_REPORT_PDFEXPORT

#define GNC_PREFS_GROUP_REPORT_PDFEXPORT   GNC_PREFS_GROUP_GENERAL_REPORT ".pdf-export"

Definition at line 1870 of file gnc-plugin-page-report.cpp.

◆ GNC_TYPE_PLUGIN_PAGE_REPORT

#define GNC_TYPE_PLUGIN_PAGE_REPORT   (gnc_plugin_page_report_get_type ())

Definition at line 46 of file gnc-plugin-page-report.h.

◆ SCHEME_OPTIONS

#define SCHEME_OPTIONS   "SchemeOptions"

The key name used it the state file for storing the report options.

Definition at line 908 of file gnc-plugin-page-report.cpp.

◆ SCHEME_OPTIONS_N

#define SCHEME_OPTIONS_N   "SchemeOptions%d"

Definition at line 909 of file gnc-plugin-page-report.cpp.

◆ WINDOW_REPORT_CM_CLASS

#define WINDOW_REPORT_CM_CLASS   "window-report"

Definition at line 55 of file gnc-plugin-page-report.h.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum

Definition at line 94 of file gnc-plugin-page-report.cpp.

95{
96 PROP_0,
97 PROP_REPORT_ID,
98};

Function Documentation

◆ gnc_main_window_open_report()

void gnc_main_window_open_report ( int  report_id,
GncMainWindow *  window 
)

Definition at line 2107 of file gnc-plugin-page-report.cpp.

2108{
2109 GncPluginPage *reportPage;
2110
2111 if (window)
2112 g_return_if_fail(GNC_IS_MAIN_WINDOW(window));
2113
2114 reportPage = gnc_plugin_page_report_new( report_id );
2115 gnc_main_window_open_page( window, reportPage );
2116}

◆ gnc_main_window_open_report_url()

void gnc_main_window_open_report_url ( const char *  url,
GncMainWindow *  window 
)

Definition at line 2119 of file gnc-plugin-page-report.cpp.

2120{
2121 GncPluginPage *reportPage;
2122
2123 DEBUG( "report url: [%s]\n", url );
2124
2125 if (window)
2126 g_return_if_fail(GNC_IS_MAIN_WINDOW(window));
2127
2128 reportPage = gnc_plugin_page_report_new( 42 /* url? */ );
2129 gnc_main_window_open_page( window, reportPage );
2130}

◆ gnc_plugin_page_report_add_edited_report()

void gnc_plugin_page_report_add_edited_report ( GncPluginPageReportPrivate priv,
SCM  report 
)

Definition at line 1363 of file gnc-plugin-page-report.cpp.

1365{
1366 SCM new_edited = scm_cons(report, priv->edited_reports);
1367 if (priv->edited_reports != SCM_EOL)
1368 scm_gc_unprotect_object(priv->edited_reports);
1369 priv->edited_reports = new_edited;
1370 if (new_edited != SCM_EOL)
1371 scm_gc_protect_object(priv->edited_reports);
1372}

◆ gnc_plugin_page_report_destroy()

void gnc_plugin_page_report_destroy ( GncPluginPageReportPrivate priv)

Definition at line 1162 of file gnc-plugin-page-report.cpp.

1163{
1164 SCM get_editor = scm_c_eval_string("gnc:report-editor-widget");
1165 SCM set_editor = scm_c_eval_string("gnc:report-set-editor-widget!");
1166 SCM edited, editor;
1167
1168 /* close any open editors */
1169 for (edited = scm_list_copy(priv->edited_reports); !scm_is_null(edited);
1170 edited = SCM_CDR(edited))
1171 {
1172 editor = scm_call_1(get_editor, SCM_CAR(edited));
1173 scm_call_2(set_editor, SCM_CAR(edited), SCM_BOOL_F);
1174 if (editor != SCM_BOOL_F)
1175 {
1176#define FUNC_NAME "gtk_widget_destroy"
1177 auto w{static_cast<GtkWidget*>(SWIG_MustGetPtr(editor, SWIG_TypeQuery("_p_GtkWidget"), 1, 0))};
1178#undef FUNC_NAME
1179 gtk_widget_destroy(GTK_WIDGET(w));
1180 }
1181 }
1182
1183 if (priv->initial_odb)
1184 {
1185//Remove this if there's a double-free
1186 gnc_option_db_destroy(priv->initial_odb);
1187 priv->initial_odb = nullptr;
1188 }
1189
1190 gnc_html_destroy(priv->html);
1191 priv->html = nullptr;
1192
1193 g_object_unref(priv->container);
1194 priv->container = nullptr;
1195
1196 if (priv->cur_report != SCM_BOOL_F)
1197 scm_gc_unprotect_object(priv->cur_report);
1198 if (priv->edited_reports != SCM_EOL)
1199 scm_gc_unprotect_object(priv->edited_reports);
1200}

◆ gnc_plugin_page_report_get_type()

GType gnc_plugin_page_report_get_type ( void  )
Returns
the type number for an "report" plugin page.

◆ gnc_plugin_page_report_new()

GncPluginPage * gnc_plugin_page_report_new ( int  reportId)
Parameters
reportIdThe scheme-defined report identifier
Returns
a new "report" plugin page.

Definition at line 1340 of file gnc-plugin-page-report.cpp.

1341{
1342 DEBUG( "report id = %d", reportId );
1343 auto plugin_page{g_object_new(GNC_TYPE_PLUGIN_PAGE_REPORT, "report-id",
1344 reportId, nullptr)};
1345 DEBUG( "plugin_page: %p", plugin_page );
1346 DEBUG( "set %d on page %p", reportId, plugin_page );
1347 return GNC_PLUGIN_PAGE( plugin_page );
1348}

◆ gnc_plugin_page_report_raise_editor()

void gnc_plugin_page_report_raise_editor ( SCM  report)

Definition at line 1375 of file gnc-plugin-page-report.cpp.

1376{
1377 SCM get_editor = scm_c_eval_string("gnc:report-editor-widget");
1378 SCM editor = scm_call_1(get_editor, report);
1379#define FUNC_NAME "gtk_window_present"
1380 auto w{static_cast<GtkWidget *>(SWIG_MustGetPtr(editor, SWIG_TypeQuery("_p_GtkWidget"), 1, 0))};
1381#undef FUNC_NAME
1382 gtk_window_present(GTK_WINDOW(w));
1383}

◆ gnc_plugin_page_report_reload()

void gnc_plugin_page_report_reload ( GncPluginPageReport report)

Definition at line 1455 of file gnc-plugin-page-report.cpp.

1456{
1457 gnc_plugin_page_report_reload_cb (nullptr, nullptr, report);
1458}

◆ gnc_plugin_page_report_remove_edited_report()

void gnc_plugin_page_report_remove_edited_report ( GncPluginPageReportPrivate priv,
SCM  report 
)

Definition at line 1351 of file gnc-plugin-page-report.cpp.

1353{
1354 SCM new_edited = scm_delete(priv->edited_reports, report);
1355 if (priv->edited_reports != SCM_EOL)
1356 scm_gc_unprotect_object(priv->edited_reports);
1357 priv->edited_reports = new_edited;
1358 if (new_edited != SCM_EOL)
1359 scm_gc_protect_object(priv->edited_reports);
1360}