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"
54static QofLogModule log_module = GNC_MOD_GUI;
56static constexpr const char* DIALOG_OPTIONS_CM_CLASS{
"dialog-options"};
57static constexpr const char* GNC_PREFS_GROUP{
"dialogs.options"};
63#define MAX_TAB_COUNT 6
75static void dialog_reset_cb(GtkWidget * w, gpointer data);
76static void dialog_list_select_cb (GtkTreeSelection *selection, gpointer data);
77static void component_close_handler (gpointer data);
79static inline GtkWidget*
const
80option_get_gtk_widget (
const GncOption* option)
82 if (!option)
return nullptr;
85 return ui_item->get_widget();
91dialog_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);
109GncOptionsDialog::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"));
118GncOptionsDialog::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(); }
137gnc_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)
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);
152 catch(std::bad_any_cast& err)
154 PERR(
"Bad widget changed callback type %s", err.what());
158 dialog_changed_internal(widget,
true);
162gnc_option_changed_option_cb(GtkWidget *dummy,
GncOption* option)
165 auto widget{option_get_gtk_widget(option)};
166 gnc_option_changed_widget_cb(widget, option);
171template<GncOptionUIType type> GtkWidget*
172create_option_widget(
GncOption& option, GtkGrid*, GtkLabel*,
char*, GtkWidget**,
179gnc_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);
207create_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);
231create_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);
336GncOptionsDialog::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);
374void 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);
385void GncOptionsDialog::call_help_cb() noexcept
388 (m_help_cb)(
this, m_help_cb_data);
391void 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);
404void GncOptionsDialog::call_book_help_cb() noexcept
411void 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();
460dialog_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
464 if (event->keyval == GDK_KEY_Escape)
466 component_close_handler (win);
474dialog_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);
501dialog_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);
518component_close_handler (gpointer data)
521 dialog_cancel_button_cb (NULL, win);
534GncOptionsDialog::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));
625GncOptionsDialog::~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);
644GncOptionsDialog::set_apply_cb(GncOptionsDialogCallback cb, gpointer data)
noexcept
647 m_apply_cb_data = data;
651GncOptionsDialog::set_help_cb(GncOptionsDialogCallback cb, gpointer data)
noexcept
654 m_help_cb_data = data;
658GncOptionsDialog::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);
672GncOptionsDialog::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);
684GncOptionsDialog::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),
Account handling public routines.
Holds all of the options for a book, report, or stylesheet, organized by GncOptionSections.
class GncOptionGtkUIItem Gtk-specific Interface class for Option Widget
class GncOptionSection The upper-level classification implementation.
static void create(GncOption &option, GtkGrid *page, int row)
Create a widget.
Holds a pointer to the UI item which will control the option and an enum representing the type of the...
Represents the public interface for an option.
Implementation details for GncOptionDB.
The primary C++ interface to options for books, reports, and stylesheets.
Generic api to store and retrieve preferences.
bool is_changed() const noexcept
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...
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.
#define PINFO(format, args...)
Print an informational note.
#define LEAVE(format, args...)
Print a function exit debugging message.
#define PERR(format, args...)
Log a serious error.
#define ENTER(format, args...)
Print a function entry debugging message.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.