GnuCash  5.6-150-g038405b370+
dialog-options.cpp
1 /********************************************************************\
2  * dialog-options.cpp -- option handling *
3  * Copyright (C) 1998-2000 Linas Vepstas *
4  * Copyright (c) 2006 David Hampton <hampton@employees.org> *
5  * Copyright (c) 2011 Robert Fewell *
6  * Copyright 2020 John Ralls *
7  * *
8  * This program is free software; you can redistribute it and/or *
9  * modify it under the terms of the GNU General Public License as *
10  * published by the Free Software Foundation; either version 2 of *
11  * the License, or (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License*
19  * along with this program; if not, contact: *
20  * *
21  * Free Software Foundation Voice: +1-617-542-5942 *
22  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
23  * Boston, MA 02110-1301, USA gnu@gnu.org *
24 \********************************************************************/
25 
26 #include <config.h> // Need this to include Account.h
27 
28 #include <Account.h> // To include as C++ overriding later indirect includes
29 #include <gtk/gtk.h>
30 #include <gdk/gdk.h>
31 #include <glib/gi18n.h>
32 #include <gnc-optiondb.hpp>
33 #include <gnc-optiondb-impl.hpp>
34 #include "dialog-options.hpp"
35 #include <libguile.h>
36 
37 #include <qofbookslots.h> // for OPTION_SECTION_ACCOUNTS
38 
39 #include "dialog-utils.h"
40 #include "gnc-component-manager.h"
41 #include <gnc-prefs.h> // for GNC_PREFS_NUM_SOURCE
42 #include "gnc-session.h" // for gnc_get_current_session
43 #include "gnc-ui.h" // for DF_MANUAL
44 
45 #include <any>
46 #include <iostream>
47 #include <sstream>
48 
49 #include "gnc-option-gtk-ui.hpp"
50 
51 #define GNC_PREF_CLOCK_24H "clock-24h"
52 
53 /* This static indicates the debugging module that this .o belongs to. */
54 static QofLogModule log_module = GNC_MOD_GUI;
55 
56 static constexpr const char* DIALOG_OPTIONS_CM_CLASS{"dialog-options"};
57 static constexpr const char* GNC_PREFS_GROUP{"dialogs.options"};
58 
59 /*
60  * Point where preferences switch control method from a set of
61  * notebook tabs to a list.
62  */
63 #define MAX_TAB_COUNT 6
64 
65 
66 
67 enum page_tree
68 {
69  PAGE_INDEX = 0,
70  PAGE_NAME,
71  NUM_COLUMNS
72 };
73 
74 
75 static void dialog_reset_cb(GtkWidget * w, gpointer data);
76 static void dialog_list_select_cb (GtkTreeSelection *selection, gpointer data);
77 static void component_close_handler (gpointer data);
78 
79 static inline GtkWidget* const
80 option_get_gtk_widget (const GncOption* option)
81 {
82  if (!option) return nullptr;
83  auto ui_item{dynamic_cast<const GncOptionGtkUIItem*>(option->get_ui_item())};
84  if (ui_item)
85  return ui_item->get_widget();
86 
87  return nullptr;
88 }
89 
90 static void
91 dialog_changed_internal (GtkWidget *widget, bool sensitive)
92 {
93  g_return_if_fail(widget);
94 
95  auto toplevel{gtk_widget_get_toplevel(widget)};
96  if (toplevel == widget && !GTK_IS_WINDOW(toplevel))
97  return;
98  g_assert(toplevel && GTK_IS_WINDOW(toplevel));
99 
100  auto option_win =
101  static_cast<GncOptionsDialog*>(g_object_get_data(G_OBJECT(toplevel),
102  "optionwin"));
103 
104  if (option_win) // this null when part of assistant
105  option_win->set_sensitive(sensitive);
106 }
107 
108 void
109 GncOptionsDialog::set_sensitive(bool sensitive) noexcept
110 {
111  gtk_widget_set_sensitive (GTK_WIDGET(m_apply_button), sensitive);
112  gtk_widget_set_sensitive (GTK_WIDGET(m_ok_button), sensitive);
113  gtk_button_set_label (m_cancel_button,
114  sensitive ? _("_Cancel") : _("_Close"));
115 }
116 
117 void
118 GncOptionsDialog::changed() noexcept
119 {
120  set_sensitive(true);
121 }
122 
123 struct SCMDeleter {
124  void operator()(SCM cb) { scm_gc_unprotect_object(cb); }
125 };
126 
128 {
129  std::unique_ptr<scm_unused_struct, SCMDeleter> m_callback;
130 public:
131  SCMCallbackWrapper(SCM cb) : m_callback{scm_gc_protect_object(cb)} {}
132  SCMCallbackWrapper(const SCMCallbackWrapper& cbw) : m_callback{scm_gc_protect_object(cbw.get())} {}
133  SCM get() const { return m_callback.get(); }
134 };
135 
136 void
137 gnc_option_changed_widget_cb(GtkWidget *widget, GncOption* option)
138 {
139  if (!option || option->is_internal()) return;
140  auto ui_item{option->get_ui_item()};
141  g_return_if_fail(ui_item);
142  auto& widget_changed_cb{option->get_widget_changed()};
143  auto gtk_ui_item{dynamic_cast<GncOptionGtkUIItem*>(ui_item)};
144  if (widget_changed_cb.has_value() && gtk_ui_item)
145  {
146  try
147  {
148  auto cb{std::any_cast<SCMCallbackWrapper>(widget_changed_cb)};
149  SCM widget_value{gtk_ui_item->get_widget_scm_value(*option)};
150  scm_call_1(cb.get(), widget_value);
151  }
152  catch(std::bad_any_cast& err)
153  {
154  PERR("Bad widget changed callback type %s", err.what());
155  }
156  }
157  const_cast<GncOptionUIItem*>(ui_item)->set_dirty(true);
158  dialog_changed_internal(widget, true);
159 }
160 
161 void
162 gnc_option_changed_option_cb(GtkWidget *dummy, GncOption* option)
163 {
164  if (!option) return;
165  auto widget{option_get_gtk_widget(option)};
166  gnc_option_changed_widget_cb(widget, option);
167 }
168 
169 
170 // This do-nothing template is specialized for each GncOptionUIType.
171 template<GncOptionUIType type> GtkWidget*
172 create_option_widget(GncOption& option, GtkGrid*, GtkLabel*, char*, GtkWidget**,
173  bool*)
174 {
175  return nullptr;
176 }
177 
178 static void
179 gnc_option_set_ui_widget(GncOption& option, GtkGrid *page_box, gint grid_row)
180 {
181  ENTER("option %p(%s), box %p",
182  &option, option.get_name().c_str(), page_box);
183  auto type = option.get_ui_type();
184  if (type == GncOptionUIType::INTERNAL)
185  {
186  LEAVE("internal type");
187  return;
188  }
189 
190  GncOptionUIFactory::create(option, page_box, grid_row);
191 
192  LEAVE(" ");
193 }
194 
195 static GtkBox*
196 create_content_box()
197 {
198  auto content_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
199  gtk_widget_set_name (content_box, "page-content-box");
200  gtk_box_set_homogeneous (GTK_BOX (content_box), FALSE);
201 
202  gtk_container_set_border_width(GTK_CONTAINER(content_box), 12);
203  return GTK_BOX(content_box);
204 }
205 
206 static GtkGrid*
207 create_options_box(GtkBox* content_box)
208 {
209  auto options_scrolled_win = gtk_scrolled_window_new(NULL, NULL);
210  gtk_box_pack_start(GTK_BOX(content_box), options_scrolled_win,
211  TRUE, TRUE, 0);
212 
213  /* Build space for the content - the options box */
214  auto options_box = gtk_grid_new(); // this will have two columns
215  gtk_widget_set_name (options_box, "options-box");
216  gtk_grid_set_row_homogeneous (GTK_GRID(options_box), FALSE);
217  gtk_grid_set_column_homogeneous (GTK_GRID(options_box), FALSE);
218  gtk_grid_set_row_spacing (GTK_GRID(options_box), 6);
219  gtk_grid_set_column_spacing (GTK_GRID(options_box), 6);
220  gtk_widget_set_halign (GTK_WIDGET(options_box), GTK_ALIGN_START);
221 
222  gtk_container_set_border_width(GTK_CONTAINER(options_box), 0);
223  gtk_container_add (GTK_CONTAINER(options_scrolled_win),
224  GTK_WIDGET(options_box));
225  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(options_scrolled_win),
226  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
227  return GTK_GRID(options_box);
228 }
229 
230 static GtkButtonBox*
231 create_reset_button_box(GtkBox* page_content_box)
232 {
233  auto buttonbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
234  gtk_button_box_set_layout (GTK_BUTTON_BOX (buttonbox),
235  GTK_BUTTONBOX_EDGE);
236  gtk_container_set_border_width(GTK_CONTAINER (buttonbox), 5);
237  gtk_box_pack_end(GTK_BOX(page_content_box), buttonbox, FALSE, FALSE, 0);
238  return GTK_BUTTON_BOX(buttonbox);
239 }
240 
241 static int
242 setup_notebook_pages(GncOptionsDialog* dlg, GtkBox* page_content_box,
243  const char* name)
244 {
245  auto notebook{dlg->get_notebook()};
246  auto page_count = gtk_notebook_page_num(GTK_NOTEBOOK(notebook),
247  GTK_WIDGET(page_content_box));
248 
249  if (dlg->get_page_list_view())
250  {
251  /* Build the matching list item for selecting from large page sets */
252  auto view = GTK_TREE_VIEW(dlg->get_page_list_view());
253  auto list = GTK_LIST_STORE(gtk_tree_view_get_model(view));
254 
255  PINFO("Page name is %s and page_count is %d", name, page_count);
256  GtkTreeIter iter;
257  gtk_list_store_append(list, &iter);
258  gtk_list_store_set(list, &iter,
259  PAGE_NAME, _(name),
260  PAGE_INDEX, page_count,
261  -1);
262 
263  if (page_count > MAX_TAB_COUNT - 1) /* Convert 1-based -> 0-based */
264  {
265  gtk_widget_show(dlg->get_page_list());
266  gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
267  gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
268  }
269  else
270  gtk_widget_hide(dlg->get_page_list());
271 
272  }
273  return page_count;
274 }
275 
276 static int
277 dialog_append_page(GncOptionsDialog* dlg, GncOptionSectionPtr& section)
278 {
279  auto name = section->get_name().c_str();
280  if (!name || *name == '\0')
281  return -1;
282 
283  if (strncmp(name, "__", 2) == 0)
284  return -1;
285 
286  auto page_label = gtk_label_new(_(name));
287  PINFO("Page_label is %s", _(name));
288  gtk_widget_show(page_label);
289 
290  /* Build this options page */
291  auto page_content_box = create_content_box();
292  auto options_box = create_options_box(page_content_box);
293 
294  /* Create all the options */
295  size_t row = 0;
296  section->foreach_option(
297  [options_box, &row](GncOption& option) {
298  g_object_set_data (G_OBJECT(options_box), "options-grid-row",
299  GINT_TO_POINTER(row));
300  gnc_option_set_ui_widget(option, GTK_GRID(options_box), row);
301  ++row;
302  });
303 
304  /* Add a button box at the bottom of the page */
305  auto buttonbox = create_reset_button_box(page_content_box);
306  /* The reset button on each option page */
307  auto reset_button = gtk_button_new_with_label (_("Reset defaults"));
308  gtk_widget_set_tooltip_text(reset_button,
309  _("Reset all values to their defaults."));
310 
311  g_signal_connect(G_OBJECT(reset_button), "clicked",
312  G_CALLBACK(dialog_reset_cb), dlg);
313  g_object_set_data(G_OBJECT(reset_button), "section",
314  static_cast<void*>(section.get()));
315  gtk_box_pack_end(GTK_BOX(buttonbox), reset_button, FALSE, FALSE, 0);
316  gtk_widget_show_all(GTK_WIDGET(page_content_box));
317  gtk_notebook_append_page(GTK_NOTEBOOK(dlg->get_notebook()),
318  GTK_WIDGET(page_content_box), page_label);
319 
320  /* Switch to selection from a list if the page count threshold is reached */
321  /* Run any callbacks on the default widget values. */
322  section->foreach_option(
323  [](GncOption& option) {
324  gnc_option_changed_option_cb(nullptr, &option);
325  });
326  return setup_notebook_pages(dlg, page_content_box, name);
327 }
328 
335 void
336 GncOptionsDialog::build_contents(GncOptionDB *odb, bool show_dialog)
337 {
338  gint default_page = -1;
339 
340  g_return_if_fail (odb != NULL);
341 
342  m_option_db = odb;
343 
344  auto default_section = odb->get_default_section();
345 
346  PINFO("Default Section name is %s",
347  default_section ? default_section->get_name().c_str() : "NULL");
348 
349  odb->foreach_section(
350  [this, default_section, &default_page]
351  (GncOptionSectionPtr& section) {
352  auto page = dialog_append_page(this, section);
353  if (default_section && section.get() == default_section)
354  default_page = page;
355  });
356 
357  gtk_notebook_popup_enable(GTK_NOTEBOOK(m_notebook));
358  if (default_page >= 0)
359  {
360  /* Find the page list and set the selection to the default page */
361  auto selection{gtk_tree_view_get_selection(GTK_TREE_VIEW(m_page_list_view))};
362  GtkTreeIter iter;
363 
364  auto model{gtk_tree_view_get_model(GTK_TREE_VIEW(m_page_list_view))};
365  gtk_tree_model_iter_nth_child(model, &iter, NULL, default_page);
366  gtk_tree_selection_select_iter (selection, &iter);
367  gtk_notebook_set_current_page(GTK_NOTEBOOK(m_notebook), default_page);
368  }
369  dialog_changed_internal(m_window, FALSE);
370  if (show_dialog)
371  gtk_widget_show(m_window);
372 }
373 
374 void GncOptionsDialog::call_apply_cb() noexcept
375 {
376  auto close_cb = m_close_cb;
377 
378  m_close_cb = nullptr;
379  if (m_apply_cb)
380  (m_apply_cb)(this, m_apply_cb_data);
381  m_close_cb = close_cb;
382  set_sensitive(false);
383 }
384 
385 void GncOptionsDialog::call_help_cb() noexcept
386 {
387  if (m_help_cb)
388  (m_help_cb)(this, m_help_cb_data);
389 }
390 
391 void GncOptionsDialog::call_close_cb() noexcept
392 {
393  if (m_close_cb)
394  {
395  gtk_window_close(GTK_WINDOW(m_window));
396  (m_close_cb)(this, m_close_cb_data);
397  }
398  else
399  {
400  gtk_widget_hide(m_window);
401  }
402 }
403 
404 void GncOptionsDialog::call_book_help_cb() noexcept
405 {
406 /* if (m_book_options_help_cb)
407  (m_book_options_help_cb)(this, m_book_options_help_cb_data);
408 */
409 }
410 
411 void GncOptionsDialog::call_style_sheet_help_cb() noexcept
412 {
413 /*
414  if (m_style_sheet_help_cb)
415  (m_style_shet_help_cb)(this, m_style_sheet_help_cb_data);
416 */
417 }
418 
419 // Help button signal handler
420 static void
421 dialog_help_button_cb(GtkWidget * widget, GncOptionsDialog *win)
422 {
423  win->call_help_cb();
424 }
425 
426 // Cancel/close button clicked signal handler
427 static void
428 dialog_cancel_button_cb(GtkWidget * widget, GncOptionsDialog *win)
429 {
430  gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(win->get_widget()));
431  win->call_close_cb();
432 }
433 
434 // Apply button clicked signal handler
435 static void
436 dialog_apply_button_cb(GtkWidget * widget, GncOptionsDialog *win)
437 {
438  gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(win->get_widget()));
439  win->call_apply_cb();
440 }
441 
442 // OK Button clicked signal handler
443 static void
444 dialog_ok_button_cb(GtkWidget * widget, GncOptionsDialog *win)
445 {
446  win->call_apply_cb();
447  gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(win->get_widget()));
448  win->call_close_cb();
449 }
450 
451 // "destroy" signal handler
452 static void
453 dialog_destroy_cb (GtkWidget *object, GncOptionsDialog *win)
454 {
455  win->call_close_cb();
456 }
457 
458 // "key_press_event" signal handler
459 static int
460 dialog_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
461 {
462  GncOptionsDialog *win = static_cast<decltype(win)>(data);
463 
464  if (event->keyval == GDK_KEY_Escape)
465  {
466  component_close_handler (win);
467  return TRUE;
468  }
469  else
470  return FALSE;
471 }
472 
473 static void
474 dialog_reset_cb(GtkWidget * w, gpointer data)
475 {
476  GncOptionsDialog *win = static_cast<decltype(win)>(data);
477  gpointer val;
478  bool dialog_changed = false;
479 
480  val = g_object_get_data(G_OBJECT(w), "section");
481  g_return_if_fail (val);
482  g_return_if_fail (win);
483 
484  auto section = static_cast<GncOptionSection*>(val);
485  section->foreach_option(
486  [&dialog_changed](GncOption& option) {
487  if (option.is_changed())
488  {
489  option.reset_default_value();
490  option.get_ui_item()->set_dirty(true);
491  dialog_changed = true;
492  }
493  option.set_ui_item_from_option();
494  });
495 
496  dialog_changed_internal (win->get_widget(), dialog_changed);
497 }
498 
499 // changed signal handler
500 static void
501 dialog_list_select_cb (GtkTreeSelection *selection, gpointer data)
502 {
503  GncOptionsDialog * win = static_cast<decltype(win)>(data);
504  GtkTreeModel *list;
505  GtkTreeIter iter;
506  gint index = 0;
507 
508  if (!gtk_tree_selection_get_selected(selection, &list, &iter))
509  return;
510  gtk_tree_model_get(list, &iter,
511  PAGE_INDEX, &index,
512  -1);
513  PINFO("Index is %d", index);
514  gtk_notebook_set_current_page(GTK_NOTEBOOK(win->get_notebook()), index);
515 }
516 
517 static void
518 component_close_handler (gpointer data)
519 {
520  GncOptionsDialog *win = static_cast<decltype(win)>(data);
521  dialog_cancel_button_cb (NULL, win);
522 }
523 
534 GncOptionsDialog::GncOptionsDialog(bool modal, const char* title,
535  const char* component_class,
536  GtkWindow *parent) :
537  m_component_class{component_class ? component_class : DIALOG_OPTIONS_CM_CLASS}
538 {
539  auto builder = gtk_builder_new();
540  gnc_builder_add_from_file (builder, "dialog-options.glade", "gnucash_options_window");
541  m_window = GTK_WIDGET(gtk_builder_get_object (builder, "gnucash_options_window"));
542  g_object_ref(m_window);
543  m_page_list = GTK_WIDGET(gtk_builder_get_object (builder, "page_list_scroll"));
544  g_object_set_data(G_OBJECT(m_window), "optionwin", this);
545 
546  // Set the name for this dialog so it can be easily manipulated with css
547  gtk_widget_set_name (GTK_WIDGET(m_window), "gnc-id-options");
548 
549  /* Page List */
550 
551  m_page_list_view = GTK_WIDGET(gtk_builder_get_object (builder, "page_list_treeview"));
552 
553  auto view = GTK_TREE_VIEW(m_page_list_view);
554 
555  auto store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_INT, G_TYPE_STRING);
556  gtk_tree_view_set_model(view, GTK_TREE_MODEL(store));
557  g_object_unref(store);
558 
559  auto renderer = gtk_cell_renderer_text_new();
560  auto column =
561  gtk_tree_view_column_new_with_attributes(_("Page"), renderer,
562  "text", PAGE_NAME,
563  nullptr);
564  gtk_tree_view_append_column(view, column);
565 
566  gtk_tree_view_column_set_alignment(column, 0.5);
567 
568  auto selection = gtk_tree_view_get_selection(view);
569  gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
570  g_signal_connect (selection, "changed",
571  G_CALLBACK (dialog_list_select_cb), this);
572 
573  m_help_button = GTK_BUTTON(gtk_builder_get_object (builder, "helpbutton"));
574  g_signal_connect(m_help_button, "clicked",
575  G_CALLBACK(dialog_help_button_cb), this);
576  m_cancel_button = GTK_BUTTON(gtk_builder_get_object (builder, "cancelbutton"));
577  g_signal_connect(m_cancel_button, "clicked",
578  G_CALLBACK(dialog_cancel_button_cb), this);
579  m_apply_button = GTK_BUTTON(gtk_builder_get_object (builder, "applybutton"));
580  g_signal_connect(m_apply_button, "clicked",
581  G_CALLBACK(dialog_apply_button_cb), this);
582  m_ok_button = GTK_BUTTON(gtk_builder_get_object (builder, "okbutton"));
583  g_signal_connect(m_ok_button, "clicked",
584  G_CALLBACK(dialog_ok_button_cb), this);
585 
586  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func,
587  this);
588 
589  // when added to a page of the hierarchy assistant there will be no parent
590  if (parent)
591  gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(m_window),
592  parent);
593 
594  if (title)
595  gtk_window_set_title(GTK_WINDOW(m_window), title);
596 
597  /* modal */
598  if (modal)
599  gtk_widget_hide (GTK_WIDGET(m_apply_button));
600 
601  /* glade doesn't support a notebook with zero pages */
602  auto hbox = GTK_WIDGET(gtk_builder_get_object (builder,
603  "notebook_placeholder"));
604  m_notebook = gtk_notebook_new();
605 
606  gtk_widget_set_vexpand (m_notebook, TRUE);
607 
608  gtk_widget_show(m_notebook);
609  gtk_box_pack_start(GTK_BOX(hbox), m_notebook, TRUE, TRUE, 5);
610 
611  auto component_id = gnc_register_gui_component (m_component_class,
612  nullptr,
613  component_close_handler,
614  this);
615  gnc_gui_component_set_session (component_id, gnc_get_current_session());
616 
617  g_signal_connect (m_window, "destroy", G_CALLBACK(dialog_destroy_cb), this);
618 
619  g_signal_connect (m_window, "key_press_event",
620  G_CALLBACK(dialog_window_key_press_cb), this);
621 
622  g_object_unref(G_OBJECT(builder));
623 }
624 
625 GncOptionsDialog::~GncOptionsDialog()
626 {
627  if (m_destroying)
628  return;
629  m_destroying = true;
630  gnc_unregister_gui_component_by_data(m_component_class, this);
631  g_signal_handlers_disconnect_by_func(m_window, (gpointer)dialog_destroy_cb, this);
632  g_signal_handlers_disconnect_by_func(m_window, (gpointer)dialog_window_key_press_cb, this);
633  m_option_db->foreach_section([](GncOptionSectionPtr& section)
634  {
635  section->foreach_option([](GncOption& option)
636  {
637  option.set_ui_item(std::unique_ptr<GncOptionUIItem>(nullptr));
638  });
639  });
640  g_object_unref(m_window);
641 }
642 
643 void
644 GncOptionsDialog::set_apply_cb(GncOptionsDialogCallback cb, gpointer data) noexcept
645 {
646  m_apply_cb = cb;
647  m_apply_cb_data = data;
648 }
649 
650 void
651 GncOptionsDialog::set_help_cb(GncOptionsDialogCallback cb, gpointer data) noexcept
652 {
653  m_help_cb = cb;
654  m_help_cb_data = data;
655 }
656 
657 void
658 GncOptionsDialog::set_close_cb( GncOptionsDialogCallback cb, gpointer data) noexcept
659 {
660  m_close_cb = cb;
661  m_close_cb_data = data;
662 }
663 
664 
665 static void
666 gnc_book_options_help_cb (GncOptionsDialog *win, gpointer dat)
667 {
668  gnc_gnome_help (GTK_WINDOW (win->get_widget()), DF_MANUAL, DL_BOOK_OPTIONS);
669 }
670 
671 void
672 GncOptionsDialog::set_book_help_cb() noexcept
673 {
674  set_help_cb((GncOptionsDialogCallback)gnc_book_options_help_cb, nullptr);
675 }
676 
677 static void
678 gnc_style_sheet_options_help_cb (GncOptionsDialog *win, gpointer dat)
679 {
680  gnc_gnome_help (GTK_WINDOW(win->get_widget()), DF_MANUAL, DL_STYLE_SHEET);
681 }
682 
683 void
684 GncOptionsDialog::set_style_sheet_help_cb () noexcept
685 {
686  set_help_cb ((GncOptionsDialogCallback)gnc_style_sheet_options_help_cb,
687  nullptr);
688 }
689 
690 
691 
692 void
694 {
695  if (!odb) return;
696  auto num_split_action = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL,
697  GNC_PREF_NUM_SOURCE);
698  if (num_split_action)
699  {
700  auto option{odb->find_option(OPTION_SECTION_ACCOUNTS,
701  OPTION_NAME_NUM_FIELD_SOURCE)};
702  auto num_source_button{option_get_gtk_widget(option)};
703  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (num_source_button),
704  num_split_action);
705  }
706 }
707 
Holds all of the options for a book, report, or stylesheet, organized by GncOptionSections.
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
bool is_changed() const noexcept
Definition: gnc-option.cpp:314
#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
Represents the public interface for an option.
Definition: gnc-option.hpp:135
void gnc_options_dialog_set_new_book_option_values(GncOptionDB *odb)
Set the initial values of new book options to values specified in user preferences.
Account handling public routines.
void gnc_gnome_help(GtkWindow *parent, const char *file_name, const char *anchor)
Launch the systems default help browser, gnome&#39;s yelp for linux, and open to a given link within a gi...
class GncOptionSection The upper-level classification implementation.
Generic api to store and retrieve preferences.
The primary C++ interface to options for books, reports, and stylesheets.
Holds a pointer to the UI item which will control the option and an enum representing the type of the...
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
static void create(GncOption &option, GtkGrid *page, int row)
Create a widget.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
Implementation details for GncOptionDB.
class GncOptionGtkUIItem Gtk-specific Interface class for Option Widget