31 #include <glib/gi18n.h> 34 #include "dialog-options.hpp" 37 #include <qofbookslots.h> 39 #include "dialog-utils.h" 40 #include "gnc-component-manager.h" 42 #include "gnc-session.h" 49 #include "gnc-option-gtk-ui.hpp" 51 #define GNC_PREF_CLOCK_24H "clock-24h" 54 static QofLogModule log_module = GNC_MOD_GUI;
56 static constexpr
const char* DIALOG_OPTIONS_CM_CLASS{
"dialog-options"};
57 static constexpr
const char* GNC_PREFS_GROUP{
"dialogs.options"};
63 #define MAX_TAB_COUNT 6 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);
79 static inline GtkWidget*
const 80 option_get_gtk_widget (
const GncOption* option)
82 if (!option)
return nullptr;
85 return ui_item->get_widget();
91 dialog_changed_internal (GtkWidget *widget,
bool sensitive)
93 g_return_if_fail(widget);
95 auto toplevel{gtk_widget_get_toplevel(widget)};
96 if (toplevel == widget && !GTK_IS_WINDOW(toplevel))
98 g_assert(toplevel && GTK_IS_WINDOW(toplevel));
105 option_win->set_sensitive(sensitive);
109 GncOptionsDialog::set_sensitive(
bool sensitive) noexcept
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"));
118 GncOptionsDialog::changed() noexcept
124 void operator()(SCM cb) { scm_gc_unprotect_object(cb); }
129 std::unique_ptr<scm_unused_struct, SCMDeleter> m_callback;
133 SCM
get()
const {
return m_callback.get(); }
137 gnc_option_changed_widget_cb(GtkWidget *widget,
GncOption* option)
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()};
144 if (widget_changed_cb.has_value() && gtk_ui_item)
149 SCM widget_value{gtk_ui_item->get_widget_scm_value(*option)};
150 scm_call_1(cb.get(), widget_value);
152 catch(std::bad_any_cast& err)
154 PERR(
"Bad widget changed callback type %s", err.what());
158 dialog_changed_internal(widget,
true);
162 gnc_option_changed_option_cb(GtkWidget *dummy,
GncOption* option)
165 auto widget{option_get_gtk_widget(option)};
166 gnc_option_changed_widget_cb(widget, option);
171 template<GncOptionUIType type> GtkWidget*
172 create_option_widget(
GncOption& option, GtkGrid*, GtkLabel*,
char*, GtkWidget**,
179 gnc_option_set_ui_widget(
GncOption& option, GtkGrid *page_box, gint grid_row)
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)
186 LEAVE(
"internal type");
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);
202 gtk_container_set_border_width(GTK_CONTAINER(content_box), 12);
203 return GTK_BOX(content_box);
207 create_options_box(GtkBox* content_box)
209 auto options_scrolled_win = gtk_scrolled_window_new(NULL, NULL);
210 gtk_box_pack_start(GTK_BOX(content_box), options_scrolled_win,
214 auto options_box = gtk_grid_new();
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);
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);
231 create_reset_button_box(GtkBox* page_content_box)
233 auto buttonbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
234 gtk_button_box_set_layout (GTK_BUTTON_BOX (buttonbox),
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);
245 auto notebook{dlg->get_notebook()};
246 auto page_count = gtk_notebook_page_num(GTK_NOTEBOOK(notebook),
247 GTK_WIDGET(page_content_box));
249 if (dlg->get_page_list_view())
252 auto view = GTK_TREE_VIEW(dlg->get_page_list_view());
253 auto list = GTK_LIST_STORE(gtk_tree_view_get_model(view));
255 PINFO(
"Page name is %s and page_count is %d", name, page_count);
257 gtk_list_store_append(list, &iter);
258 gtk_list_store_set(list, &iter,
260 PAGE_INDEX, page_count,
263 if (page_count > MAX_TAB_COUNT - 1)
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);
270 gtk_widget_hide(dlg->get_page_list());
279 auto name = section->get_name().c_str();
280 if (!name || *name ==
'\0')
283 if (strncmp(name,
"__", 2) == 0)
286 auto page_label = gtk_label_new(_(name));
287 PINFO(
"Page_label is %s", _(name));
288 gtk_widget_show(page_label);
291 auto page_content_box = create_content_box();
292 auto options_box = create_options_box(page_content_box);
296 section->foreach_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);
305 auto buttonbox = create_reset_button_box(page_content_box);
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."));
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);
322 section->foreach_option(
324 gnc_option_changed_option_cb(
nullptr, &option);
326 return setup_notebook_pages(dlg, page_content_box, name);
336 GncOptionsDialog::build_contents(
GncOptionDB *odb,
bool show_dialog)
338 gint default_page = -1;
340 g_return_if_fail (odb != NULL);
344 auto default_section = odb->get_default_section();
346 PINFO(
"Default Section name is %s",
347 default_section ? default_section->get_name().c_str() :
"NULL");
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)
357 gtk_notebook_popup_enable(GTK_NOTEBOOK(m_notebook));
358 if (default_page >= 0)
361 auto selection{gtk_tree_view_get_selection(GTK_TREE_VIEW(m_page_list_view))};
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);
369 dialog_changed_internal(m_window, FALSE);
371 gtk_widget_show(m_window);
374 void GncOptionsDialog::call_apply_cb() noexcept
376 auto close_cb = m_close_cb;
378 m_close_cb =
nullptr;
380 (m_apply_cb)(
this, m_apply_cb_data);
381 m_close_cb = close_cb;
382 set_sensitive(
false);
385 void GncOptionsDialog::call_help_cb() noexcept
388 (m_help_cb)(
this, m_help_cb_data);
391 void GncOptionsDialog::call_close_cb() noexcept
395 gtk_window_close(GTK_WINDOW(m_window));
396 (m_close_cb)(
this, m_close_cb_data);
400 gtk_widget_hide(m_window);
404 void GncOptionsDialog::call_book_help_cb() noexcept
411 void GncOptionsDialog::call_style_sheet_help_cb() noexcept
430 gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(win->get_widget()));
431 win->call_close_cb();
438 gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(win->get_widget()));
439 win->call_apply_cb();
446 win->call_apply_cb();
447 gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(win->get_widget()));
448 win->call_close_cb();
455 win->call_close_cb();
460 dialog_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
464 if (event->keyval == GDK_KEY_Escape)
466 component_close_handler (win);
474 dialog_reset_cb(GtkWidget * w, gpointer data)
478 bool dialog_changed =
false;
480 val = g_object_get_data(G_OBJECT(w),
"section");
481 g_return_if_fail (val);
482 g_return_if_fail (win);
485 section->foreach_option(
489 option.reset_default_value();
490 option.get_ui_item()->set_dirty(
true);
491 dialog_changed =
true;
493 option.set_ui_item_from_option();
496 dialog_changed_internal (win->get_widget(), dialog_changed);
501 dialog_list_select_cb (GtkTreeSelection *selection, gpointer data)
508 if (!gtk_tree_selection_get_selected(selection, &list, &iter))
510 gtk_tree_model_get(list, &iter,
513 PINFO(
"Index is %d", index);
514 gtk_notebook_set_current_page(GTK_NOTEBOOK(win->get_notebook()), index);
518 component_close_handler (gpointer data)
521 dialog_cancel_button_cb (NULL, win);
534 GncOptionsDialog::GncOptionsDialog(
bool modal,
const char* title,
535 const char* component_class,
537 m_component_class{component_class ? component_class : DIALOG_OPTIONS_CM_CLASS}
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);
547 gtk_widget_set_name (GTK_WIDGET(m_window),
"gnc-id-options");
551 m_page_list_view = GTK_WIDGET(gtk_builder_get_object (builder,
"page_list_treeview"));
553 auto view = GTK_TREE_VIEW(m_page_list_view);
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);
559 auto renderer = gtk_cell_renderer_text_new();
561 gtk_tree_view_column_new_with_attributes(_(
"Page"), renderer,
564 gtk_tree_view_append_column(view, column);
566 gtk_tree_view_column_set_alignment(column, 0.5);
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);
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);
586 gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func,
591 gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(m_window),
595 gtk_window_set_title(GTK_WINDOW(m_window), title);
599 gtk_widget_hide (GTK_WIDGET(m_apply_button));
602 auto hbox = GTK_WIDGET(gtk_builder_get_object (builder,
603 "notebook_placeholder"));
604 m_notebook = gtk_notebook_new();
606 gtk_widget_set_vexpand (m_notebook, TRUE);
608 gtk_widget_show(m_notebook);
609 gtk_box_pack_start(GTK_BOX(hbox), m_notebook, TRUE, TRUE, 5);
611 auto component_id = gnc_register_gui_component (m_component_class,
613 component_close_handler,
615 gnc_gui_component_set_session (component_id, gnc_get_current_session());
617 g_signal_connect (m_window,
"destroy", G_CALLBACK(dialog_destroy_cb),
this);
619 g_signal_connect (m_window,
"key_press_event",
620 G_CALLBACK(dialog_window_key_press_cb),
this);
622 g_object_unref(G_OBJECT(builder));
625 GncOptionsDialog::~GncOptionsDialog()
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)
635 section->foreach_option([](
GncOption& option)
637 option.set_ui_item(std::unique_ptr<GncOptionUIItem>(
nullptr));
640 g_object_unref(m_window);
644 GncOptionsDialog::set_apply_cb(GncOptionsDialogCallback cb, gpointer data) noexcept
647 m_apply_cb_data = data;
651 GncOptionsDialog::set_help_cb(GncOptionsDialogCallback cb, gpointer data) noexcept
654 m_help_cb_data = data;
658 GncOptionsDialog::set_close_cb( GncOptionsDialogCallback cb, gpointer data) noexcept
661 m_close_cb_data = data;
668 gnc_gnome_help (GTK_WINDOW (win->get_widget()), DF_MANUAL, DL_BOOK_OPTIONS);
672 GncOptionsDialog::set_book_help_cb() noexcept
674 set_help_cb((GncOptionsDialogCallback)gnc_book_options_help_cb,
nullptr);
680 gnc_gnome_help (GTK_WINDOW(win->get_widget()), DF_MANUAL, DL_STYLE_SHEET);
684 GncOptionsDialog::set_style_sheet_help_cb () noexcept
686 set_help_cb ((GncOptionsDialogCallback)gnc_style_sheet_options_help_cb,
697 GNC_PREF_NUM_SOURCE);
698 if (num_split_action)
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),
Holds all of the options for a book, report, or stylesheet, organized by GncOptionSections.
#define PINFO(format, args...)
Print an informational note.
bool is_changed() const noexcept
#define PERR(format, args...)
Log a serious error.
#define ENTER(format, args...)
Print a function entry debugging message.
Represents the public interface for an option.
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'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.
Implementation details for GncOptionDB.
class GncOptionGtkUIItem Gtk-specific Interface class for Option Widget