Change the Options dialogue to use GtkWindow

Change the report / book options dialogue from a GtkDialog to GtkWindow.
This removes the need for setting the transient parent which allows the
dialogue to be placed behind the main application when changing values
making it easier to see the result.
This commit is contained in:
Robert Fewell 2018-07-22 12:36:35 +01:00
parent 8edf447808
commit 5ad584ca3b
3 changed files with 155 additions and 79 deletions

View File

@ -70,6 +70,8 @@ static QofLogModule log_module = GNC_MOD_GUI;
#define DIALOG_OPTIONS_CM_CLASS "dialog-options" #define DIALOG_OPTIONS_CM_CLASS "dialog-options"
#define DIALOG_BOOK_OPTIONS_CM_CLASS "dialog-book-options" #define DIALOG_BOOK_OPTIONS_CM_CLASS "dialog-book-options"
#define GNC_PREFS_GROUP "dialogs.options"
/* /*
* Point where preferences switch control method from a set of * Point where preferences switch control method from a set of
* notebook tabs to a list. * notebook tabs to a list.
@ -86,7 +88,7 @@ static int gain_loss_accounts_in_filter = 0;
struct gnc_option_win struct gnc_option_win
{ {
GtkWidget * dialog; GtkWidget * window;
GtkWidget * notebook; GtkWidget * notebook;
GtkWidget * page_list_view; GtkWidget * page_list_view;
GtkWidget * page_list; GtkWidget * page_list;
@ -107,6 +109,9 @@ struct gnc_option_win
/* Hold on to this to unregister the right class */ /* Hold on to this to unregister the right class */
const char *component_class; const char *component_class;
/* widget being destroyed */
gboolean destroyed;
}; };
typedef enum typedef enum
@ -150,8 +155,6 @@ static currency_accounting_data *book_currency_data = NULL;
static GNCOptionWinCallback global_help_cb = NULL; static GNCOptionWinCallback global_help_cb = NULL;
gpointer global_help_cb_data = NULL; gpointer global_help_cb_data = NULL;
void gnc_options_dialog_response_cb(GtkDialog *dialog, gint response,
GNCOptionWin *window);
static void gnc_options_dialog_reset_cb(GtkWidget * w, gpointer data); static void gnc_options_dialog_reset_cb(GtkWidget * w, gpointer data);
void gnc_options_dialog_list_select_cb (GtkTreeSelection *selection, void gnc_options_dialog_list_select_cb (GtkTreeSelection *selection,
gpointer data); gpointer data);
@ -172,16 +175,42 @@ gnc_option_get_gtk_widget (GNCOption *option)
static void static void
gnc_options_dialog_changed_internal (GtkWidget *widget, gboolean sensitive) gnc_options_dialog_changed_internal (GtkWidget *widget, gboolean sensitive)
{ {
GtkDialog *dialog; while (widget && !GTK_IS_WINDOW(widget))
while (widget && !GTK_IS_DIALOG(widget))
widget = gtk_widget_get_parent(widget); widget = gtk_widget_get_parent(widget);
if (widget == NULL) if (widget == NULL)
return; return;
dialog = GTK_DIALOG(widget); /* find the ok and cancel buttons, we know where they will be so do it
gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_OK, sensitive); this way as opposed to using gtk_container_foreach, much less iteration */
gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_APPLY, sensitive); if (GTK_IS_CONTAINER(widget))
{
GList *children = gtk_container_get_children(GTK_CONTAINER(widget));
for (GList *it = children; it; it = it->next)
{
if (GTK_IS_BOX (GTK_WIDGET(it->data)))
{
GList *children = gtk_container_get_children(GTK_CONTAINER(it->data));
for (GList *it = children; it; it = it->next)
{
if (GTK_IS_BUTTON_BOX (GTK_WIDGET(it->data)))
{
GList *children = gtk_container_get_children(GTK_CONTAINER(it->data));
for (GList *it = children; it; it = it->next)
{
if (g_strcmp0 (gtk_widget_get_name(GTK_WIDGET(it->data)), "ok_button") == 0)
gtk_widget_set_sensitive (GTK_WIDGET(it->data), sensitive);
if (g_strcmp0 (gtk_widget_get_name(GTK_WIDGET(it->data)), "apply_button") == 0)
gtk_widget_set_sensitive (GTK_WIDGET(it->data), sensitive);
}
g_list_free (children);
}
}
g_list_free (children);
}
}
g_list_free (children);
}
} }
void void
@ -189,7 +218,7 @@ gnc_options_dialog_changed (GNCOptionWin *win)
{ {
if (!win) return; if (!win) return;
gnc_options_dialog_changed_internal (win->dialog, TRUE); gnc_options_dialog_changed_internal (win->window, TRUE);
} }
void void
@ -1968,15 +1997,15 @@ gnc_options_dialog_build_contents_full (GNCOptionWin *propertybox,
gtk_tree_selection_select_iter (selection, &iter); gtk_tree_selection_select_iter (selection, &iter);
gtk_notebook_set_current_page(GTK_NOTEBOOK(propertybox->notebook), default_page); gtk_notebook_set_current_page(GTK_NOTEBOOK(propertybox->notebook), default_page);
} }
gnc_options_dialog_changed_internal(propertybox->dialog, FALSE); gnc_options_dialog_changed_internal(propertybox->window, FALSE);
if (show_dialog) if (show_dialog)
gtk_widget_show(propertybox->dialog); gtk_widget_show(propertybox->window);
} }
GtkWidget * GtkWidget *
gnc_options_dialog_widget(GNCOptionWin * win) gnc_options_dialog_widget(GNCOptionWin * win)
{ {
return win->dialog; return win->window;
} }
GtkWidget * GtkWidget *
@ -1991,42 +2020,62 @@ gnc_options_dialog_notebook(GNCOptionWin * win)
return win->notebook; return win->notebook;
} }
void static void
gnc_options_dialog_response_cb(GtkDialog *dialog, gint response, GNCOptionWin *window) gnc_options_dialog_help_button_cb(GtkWidget * widget, GNCOptionWin *win)
{ {
GNCOptionWinCallback close_cb; if (win->help_cb)
(win->help_cb)(win, win->help_cb_data);
}
switch (response) static void
gnc_options_dialog_cancel_button_cb(GtkWidget * widget, GNCOptionWin *win)
{
if (win->close_cb)
(win->close_cb)(win, win->close_cb_data);
else
gtk_widget_hide(win->window);
}
static void
gnc_options_dialog_apply_button_cb(GtkWidget * widget, GNCOptionWin *win)
{
GNCOptionWinCallback close_cb = win->close_cb;
win->close_cb = NULL;
if (win->apply_cb)
win->apply_cb (win, win->apply_cb_data);
win->close_cb = close_cb;
gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(win->window));
gnc_options_dialog_changed_internal (win->window, FALSE);
}
static void
gnc_options_dialog_ok_button_cb(GtkWidget * widget, GNCOptionWin *win)
{
GNCOptionWinCallback close_cb = win->close_cb;
win->close_cb = NULL;
if (win->apply_cb)
win->apply_cb (win, win->apply_cb_data);
win->close_cb = close_cb;
gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(win->window));
if (win->close_cb)
(win->close_cb)(win, win->close_cb_data);
else
gtk_widget_hide(win->window);
}
static void
gnc_options_dialog_destroy_cb (GtkWidget *object, GNCOptionWin *win)
{
if (!win) return;
if (win->destroyed == FALSE)
{ {
case GTK_RESPONSE_HELP: if (win->close_cb)
if (window->help_cb) (win->close_cb)(win, win->close_cb_data);
(window->help_cb)(window, window->help_cb_data);
break;
case GTK_RESPONSE_OK:
case GTK_RESPONSE_APPLY:
close_cb = window->close_cb;
window->close_cb = NULL;
if (window->apply_cb)
window->apply_cb (window, window->apply_cb_data);
window->close_cb = close_cb;
if (response == GTK_RESPONSE_APPLY)
{
gnc_options_dialog_changed_internal (window->dialog, FALSE);
break;
}
/* fall through */
default:
if (window->close_cb)
{
(window->close_cb)(window, window->close_cb_data);
}
else
{
gtk_widget_hide(window->dialog);
}
break;
} }
} }
@ -2043,7 +2092,7 @@ gnc_options_dialog_reset_cb(GtkWidget * w, gpointer data)
section = (GNCOptionSection*)val; section = (GNCOptionSection*)val;
gnc_option_db_section_reset_widgets (section); gnc_option_db_section_reset_widgets (section);
gnc_options_dialog_changed_internal (win->dialog, TRUE); gnc_options_dialog_changed_internal (win->window, TRUE);
} }
void void
@ -2091,8 +2140,8 @@ gnc_options_register_stocks (void)
static void static void
component_close_handler (gpointer data) component_close_handler (gpointer data)
{ {
GNCOptionWin *window = data; GNCOptionWin *win = data;
gtk_dialog_response(GTK_DIALOG(window->dialog), GTK_RESPONSE_CANCEL); gnc_options_dialog_cancel_button_cb (NULL, win);
} }
static void static void
@ -2152,16 +2201,17 @@ gnc_options_dialog_new_modal(gboolean modal, gchar *title,
GtkBuilder *builder; GtkBuilder *builder;
GtkWidget *hbox; GtkWidget *hbox;
gint component_id; gint component_id;
GtkWidget *button;
retval = g_new0(GNCOptionWin, 1); retval = g_new0(GNCOptionWin, 1);
builder = gtk_builder_new(); builder = gtk_builder_new();
gnc_builder_add_from_file (builder, "dialog-options.glade", "gnucash_options_dialog"); gnc_builder_add_from_file (builder, "dialog-options.glade", "gnucash_options_window");
retval->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "gnucash_options_dialog")); retval->window = GTK_WIDGET(gtk_builder_get_object (builder, "gnucash_options_window"));
retval->page_list = GTK_WIDGET(gtk_builder_get_object (builder, "page_list_scroll")); retval->page_list = GTK_WIDGET(gtk_builder_get_object (builder, "page_list_scroll"));
// Set the style context for this dialog so it can be easily manipulated with css // Set the style context for this dialog so it can be easily manipulated with css
gnc_widget_set_style_context (GTK_WIDGET(retval->dialog), "GncOptionsDialog"); gnc_widget_set_style_context (GTK_WIDGET(retval->window), "GncOptionsDialog");
gtk_window_set_transient_for (GTK_WINDOW (retval->dialog), parent);
/* Page List */ /* Page List */
{ {
GtkTreeView *view; GtkTreeView *view;
@ -2189,13 +2239,23 @@ gnc_options_dialog_new_modal(gboolean modal, gchar *title,
gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
g_signal_connect (selection, "changed", g_signal_connect (selection, "changed",
G_CALLBACK (gnc_options_dialog_list_select_cb), retval); G_CALLBACK (gnc_options_dialog_list_select_cb), retval);
} }
button = GTK_WIDGET(gtk_builder_get_object (builder, "helpbutton"));
g_signal_connect(button, "clicked", G_CALLBACK(gnc_options_dialog_help_button_cb), retval);
button = GTK_WIDGET(gtk_builder_get_object (builder, "cancelbutton"));
g_signal_connect(button, "clicked", G_CALLBACK(gnc_options_dialog_cancel_button_cb), retval);
button = GTK_WIDGET(gtk_builder_get_object (builder, "applybutton"));
g_signal_connect(button, "clicked", G_CALLBACK(gnc_options_dialog_apply_button_cb), retval);
button = GTK_WIDGET(gtk_builder_get_object (builder, "okbutton"));
g_signal_connect(button, "clicked", G_CALLBACK(gnc_options_dialog_ok_button_cb), retval);
gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, retval); gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, retval);
gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(retval->window));
if (title) if (title)
gtk_window_set_title(GTK_WINDOW(retval->dialog), title); gtk_window_set_title(GTK_WINDOW(retval->window), title);
/* modal */ /* modal */
if (modal == TRUE) if (modal == TRUE)
@ -2229,20 +2289,25 @@ gnc_options_dialog_new_modal(gboolean modal, gchar *title,
GNC_ID_ACCOUNT, GNC_ID_ACCOUNT,
QOF_EVENT_MODIFY | QOF_EVENT_DESTROY); QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
} }
g_signal_connect (retval->window, "destroy",
G_CALLBACK(gnc_options_dialog_destroy_cb), retval);
g_object_unref(G_OBJECT(builder)); g_object_unref(G_OBJECT(builder));
retval->destroyed = FALSE;
return retval; return retval;
} }
/* Creates a new GNCOptionWin structure, but assumes you have your own /* Creates a new GNCOptionWin structure, but assumes you have your own
dialog widget you want to plugin */ dialog widget you want to plugin */
GNCOptionWin * GNCOptionWin *
gnc_options_dialog_new_w_dialog(gchar *title, GtkWidget *dialog) gnc_options_dialog_new_w_dialog(gchar *title, GtkWidget *window)
{ {
GNCOptionWin * retval; GNCOptionWin * retval;
retval = g_new0(GNCOptionWin, 1); retval = g_new0(GNCOptionWin, 1);
retval->dialog = dialog; retval->window = window;
return retval; return retval;
} }
@ -2286,9 +2351,10 @@ gnc_options_dialog_destroy(GNCOptionWin * win)
gnc_unregister_gui_component_by_data(win->component_class, win); gnc_unregister_gui_component_by_data(win->component_class, win);
gtk_widget_destroy(win->dialog); win->destroyed = TRUE;
gtk_widget_destroy(win->window);
win->dialog = NULL; win->window = NULL;
win->notebook = NULL; win->notebook = NULL;
win->apply_cb = NULL; win->apply_cb = NULL;
win->help_cb = NULL; win->help_cb = NULL;

View File

@ -21,6 +21,7 @@
<child name="search" schema="org.gnucash.dialogs.search"/> <child name="search" schema="org.gnucash.dialogs.search"/>
<child name="transfer" schema="org.gnucash.dialogs.transfer"/> <child name="transfer" schema="org.gnucash.dialogs.transfer"/>
<child name="trans-assoc" schema="org.gnucash.dialogs.trans-assoc"/> <child name="trans-assoc" schema="org.gnucash.dialogs.trans-assoc"/>
<child name="options" schema="org.gnucash.dialogs.options"/>
</schema> </schema>
<schema id="org.gnucash.dialogs.account" path="/org/gnucash/dialogs/account/"> <schema id="org.gnucash.dialogs.account" path="/org/gnucash/dialogs/account/">
@ -245,4 +246,14 @@
followed by the width and height of the window.</description> followed by the width and height of the window.</description>
</key> </key>
</schema> </schema>
<schema id="org.gnucash.dialogs.options" path="/org/gnucash/dialogs/options/">
<key name="last-geometry" type="(iiii)">
<default>(-1,-1,-1,-1)</default>
<summary>Last window position and size</summary>
<description>This setting describes the size and position of the window when it was last closed.
The numbers are the X and Y coordinates of the top left corner of the window
followed by the width and height of the window.</description>
</key>
</schema>
</schemalist> </schemalist>

View File

@ -1,27 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 --> <!-- Generated with glade 3.20.4 -->
<interface> <interface>
<requires lib="gtk+" version="3.10"/> <requires lib="gtk+" version="3.10"/>
<object class="GtkDialog" id="gnucash_options_dialog"> <object class="GtkWindow" id="gnucash_options_window">
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="title" translatable="yes">GnuCash Options</property>
<property name="default_width">640</property> <property name="default_width">640</property>
<property name="default_height">480</property> <property name="default_height">480</property>
<property name="type_hint">dialog</property> <child>
<signal name="response" handler="gnc_options_dialog_response_cb" swapped="no"/> <object class="GtkBox" id="dialog-vbox">
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox1">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child internal-child="action_area"> <child>
<object class="GtkButtonBox" id="dialog-action_area1"> <object class="GtkButtonBox" id="buttonbox">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="layout_style">end</property> <property name="layout_style">end</property>
<child> <child>
<object class="GtkButton" id="helpbutton1"> <object class="GtkButton" id="helpbutton">
<property name="label" translatable="yes">_Help</property> <property name="label" translatable="yes">_Help</property>
<property name="name">help_button</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="can_default">True</property> <property name="can_default">True</property>
@ -32,11 +30,13 @@
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="position">0</property> <property name="position">0</property>
<property name="secondary">True</property>
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkButton" id="cancelbutton1"> <object class="GtkButton" id="cancelbutton">
<property name="label" translatable="yes">_Cancel</property> <property name="label" translatable="yes">_Cancel</property>
<property name="name">cancel_button</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="can_default">True</property> <property name="can_default">True</property>
@ -53,6 +53,7 @@
<child> <child>
<object class="GtkButton" id="applybutton"> <object class="GtkButton" id="applybutton">
<property name="label" translatable="yes">_Apply</property> <property name="label" translatable="yes">_Apply</property>
<property name="name">apply_button</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="can_default">True</property> <property name="can_default">True</property>
@ -67,8 +68,9 @@
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkButton" id="okbutton1"> <object class="GtkButton" id="okbutton">
<property name="label" translatable="yes">_OK</property> <property name="label" translatable="yes">_OK</property>
<property name="name">ok_button</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="can_default">True</property> <property name="can_default">True</property>
@ -91,7 +93,7 @@
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkBox" id="hbox1"> <object class="GtkBox" id="hbox">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<child> <child>
@ -105,7 +107,7 @@
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<child internal-child="selection"> <child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection1"/> <object class="GtkTreeSelection" id="treeview-selection"/>
</child> </child>
</object> </object>
</child> </child>
@ -139,11 +141,8 @@
</child> </child>
</object> </object>
</child> </child>
<action-widgets> <child type="titlebar">
<action-widget response="-11">helpbutton1</action-widget> <placeholder/>
<action-widget response="-6">cancelbutton1</action-widget> </child>
<action-widget response="-10">applybutton</action-widget>
<action-widget response="-5">okbutton1</action-widget>
</action-widgets>
</object> </object>
</interface> </interface>