[gimp/tito: 2/15] Bug 708174 - Improve the original search dialog patch.
- From: Jehan Pagès <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/tito: 2/15] Bug 708174 - Improve the original search dialog patch.
- Date: Sun, 1 Dec 2013 22:39:39 +0000 (UTC)
commit e1418051da5e3a2ae896d34f33d9945b40c1275d
Author: Jehan <jehan girinstud io>
Date: Thu Sep 26 06:02:59 2013 +1200
Bug 708174 - Improve the original search dialog patch.
It uses now GIMP preferences. Several preferences removed in favor to
position/size remembered. Also now action history is tightly tied to
GimpAction and logs all action activation (however it activates), and
the show_unavailable parameter also applies to history.
Finally fix various bugs and improves code design and efficiency.
app/actions/dialogs-actions.c | 2 +-
app/config/gimpguiconfig.c | 93 +++
app/config/gimpguiconfig.h | 10 +
app/config/gimprc-blurbs.h | 9 +
app/dialogs/action-search-dialog.c | 1128 +++++++++++-------------------------
app/dialogs/action-search-dialog.h | 3 +-
app/dialogs/dialogs-constructors.c | 2 +-
app/dialogs/preferences-dialog.c | 32 +-
app/gui/gui.c | 3 +
app/gui/session.c | 105 ++++
app/widgets/Makefile.am | 2 +
app/widgets/gimpaction-history.c | 296 ++++++++++
app/widgets/gimpaction-history.h | 38 ++
app/widgets/gimpaction.c | 13 +
14 files changed, 948 insertions(+), 788 deletions(-)
---
diff --git a/app/actions/dialogs-actions.c b/app/actions/dialogs-actions.c
index 677772a..2163b59 100644
--- a/app/actions/dialogs-actions.c
+++ b/app/actions/dialogs-actions.c
@@ -265,7 +265,7 @@ static const GimpStringActionEntry dialogs_toplevel_actions[] =
GIMP_HELP_ABOUT_DIALOG },
{ "dialogs-action-search", GTK_STOCK_FIND,
- NC_("dialogs-action", "_Search and Run a Command"), NULL,
+ NC_("dialogs-action", "_Search and Run a Command"), "slash",
NC_("dialogs-action", "Search commands by keyword, and run them"),
"gimp-action-search-dialog",
GIMP_HELP_ACTION_SEARCH_DIALOG }
diff --git a/app/config/gimpguiconfig.c b/app/config/gimpguiconfig.c
index ff5dff7..fdb88f6 100644
--- a/app/config/gimpguiconfig.c
+++ b/app/config/gimpguiconfig.c
@@ -67,6 +67,13 @@ enum
PROP_SHOW_HELP_BUTTON,
PROP_HELP_LOCALES,
PROP_HELP_BROWSER,
+ PROP_SEARCH_DIALOG_X,
+ PROP_SEARCH_DIALOG_Y,
+ PROP_SEARCH_DIALOG_WIDTH,
+ PROP_SEARCH_DIALOG_HEIGHT,
+ PROP_SEARCH_DIALOG_OPACITY,
+ PROP_SEARCH_SHOW_UNAVAILABLE_ACTIONS,
+ PROP_ACTION_HISTORY_SIZE,
PROP_USER_MANUAL_ONLINE,
PROP_USER_MANUAL_ONLINE_URI,
PROP_DOCK_WINDOW_HINT,
@@ -228,6 +235,50 @@ gimp_gui_config_class_init (GimpGuiConfigClass *klass)
GIMP_TYPE_HELP_BROWSER_TYPE,
DEFAULT_HELP_BROWSER,
GIMP_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_SEARCH_DIALOG_X,
+ g_param_spec_int ("search-dialog-position-x",
+ NULL, NULL,
+ -1, 10000, -1,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ GIMP_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, PROP_SEARCH_DIALOG_Y,
+ g_param_spec_int ("search-dialog-position-y",
+ NULL, NULL,
+ -1, 10000, -1,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ GIMP_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, PROP_SEARCH_DIALOG_WIDTH,
+ g_param_spec_int ("search-dialog-width",
+ NULL, NULL,
+ -1, 10000, -1,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ GIMP_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, PROP_SEARCH_DIALOG_HEIGHT,
+ g_param_spec_int ("search-dialog-height",
+ NULL, NULL,
+ 20, 800, 200,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ GIMP_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, PROP_SEARCH_DIALOG_OPACITY,
+ g_param_spec_int ("search-dialog-opacity",
+ NULL, SEARCH_DIALOG_OPACITY_BLURB,
+ 1, 100, 100,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ GIMP_PARAM_STATIC_STRINGS));
+ /* As a default, we hide unavailable actions. */
+ GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_SEARCH_SHOW_UNAVAILABLE_ACTIONS,
+ "search-show-unavailable-actions", SEARCH_SHOW_UNAVAILABLE_BLURB,
+ FALSE,
+ GIMP_PARAM_STATIC_STRINGS);
+ GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_ACTION_HISTORY_SIZE,
+ "action-history-size", ACTION_HISTORY_SIZE_BLURB,
+ 0, 200, 20,
+ GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_USER_MANUAL_ONLINE,
"user-manual-online",
USER_MANUAL_ONLINE_BLURB,
@@ -432,6 +483,27 @@ gimp_gui_config_set_property (GObject *object,
case PROP_HELP_BROWSER:
gui_config->help_browser = g_value_get_enum (value);
break;
+ case PROP_SEARCH_DIALOG_X:
+ gui_config->search_dialog_x = g_value_get_int (value);
+ break;
+ case PROP_SEARCH_DIALOG_Y:
+ gui_config->search_dialog_y = g_value_get_int (value);
+ break;
+ case PROP_SEARCH_DIALOG_WIDTH:
+ gui_config->search_dialog_width = g_value_get_int (value);
+ break;
+ case PROP_SEARCH_DIALOG_HEIGHT:
+ gui_config->search_dialog_height = g_value_get_int (value);
+ break;
+ case PROP_SEARCH_DIALOG_OPACITY:
+ gui_config->search_dialog_opacity = g_value_get_int (value);
+ break;
+ case PROP_SEARCH_SHOW_UNAVAILABLE_ACTIONS:
+ gui_config->search_show_unavailable = g_value_get_boolean (value);
+ break;
+ case PROP_ACTION_HISTORY_SIZE:
+ gui_config->action_history_size = g_value_get_int (value);
+ break;
case PROP_USER_MANUAL_ONLINE:
gui_config->user_manual_online = g_value_get_boolean (value);
break;
@@ -558,6 +630,27 @@ gimp_gui_config_get_property (GObject *object,
case PROP_HELP_BROWSER:
g_value_set_enum (value, gui_config->help_browser);
break;
+ case PROP_SEARCH_DIALOG_X:
+ g_value_set_int (value, gui_config->search_dialog_x);
+ break;
+ case PROP_SEARCH_DIALOG_Y:
+ g_value_set_int (value, gui_config->search_dialog_y);
+ break;
+ case PROP_SEARCH_DIALOG_WIDTH:
+ g_value_set_int (value, gui_config->search_dialog_width);
+ break;
+ case PROP_SEARCH_DIALOG_HEIGHT:
+ g_value_set_int (value, gui_config->search_dialog_height);
+ break;
+ case PROP_SEARCH_DIALOG_OPACITY:
+ g_value_set_int (value, gui_config->search_dialog_opacity);
+ break;
+ case PROP_SEARCH_SHOW_UNAVAILABLE_ACTIONS:
+ g_value_set_boolean (value, gui_config->search_show_unavailable);
+ break;
+ case PROP_ACTION_HISTORY_SIZE:
+ g_value_set_int (value, gui_config->action_history_size);
+ break;
case PROP_USER_MANUAL_ONLINE:
g_value_set_boolean (value, gui_config->user_manual_online);
break;
diff --git a/app/config/gimpguiconfig.h b/app/config/gimpguiconfig.h
index e7eed9f..c015524 100644
--- a/app/config/gimpguiconfig.h
+++ b/app/config/gimpguiconfig.h
@@ -61,6 +61,16 @@ struct _GimpGuiConfig
gboolean show_help_button;
gchar *help_locales;
GimpHelpBrowserType help_browser;
+
+ /* Action Search preferences. */
+ gint search_dialog_x;
+ gint search_dialog_y;
+ gint search_dialog_width;
+ gint search_dialog_height;
+ gint search_dialog_opacity;
+ gboolean search_show_unavailable;
+ gint action_history_size;
+
gchar *web_browser;
gboolean user_manual_online;
gchar *user_manual_online_uri;
diff --git a/app/config/gimprc-blurbs.h b/app/config/gimprc-blurbs.h
index 6c2acd0..64a2764 100644
--- a/app/config/gimprc-blurbs.h
+++ b/app/config/gimprc-blurbs.h
@@ -474,4 +474,13 @@ N_("When enabled, uses OpenCL for some operations.")
"Bugs in event history buffer are frequent so in case of cursor " \
"offset problems turning it off helps."
+#define SEARCH_DIALOG_OPACITY_BLURB \
+"Opacity of the action search box."
+
+#define SEARCH_SHOW_UNAVAILABLE_BLURB \
+"When enabled, a search of actions will also return inactive actions."
+
+#define ACTION_HISTORY_SIZE_BLURB \
+"The maximum number of actions saved in history."
+
#endif /* __GIMP_RC_BLURBS_H__ */
diff --git a/app/dialogs/action-search-dialog.c b/app/dialogs/action-search-dialog.c
index 9c0f1b1..1450544 100644
--- a/app/dialogs/action-search-dialog.c
+++ b/app/dialogs/action-search-dialog.c
@@ -32,53 +32,63 @@
#include "widgets/gimpuimanager.h"
#include "widgets/gimpaction.h"
+#include "widgets/gimpaction-history.h"
+
+#include "config/gimpguiconfig.h"
+#include "core/gimp.h"
#include "action-search-dialog.h"
#include "gimp-intl.h"
-#define MAX_HISTORY_ACTIONS 20
-#define DEFAULT_HEIGHT 1
-
-gboolean action_search_run_result_action (void);
-static GtkWidget * action_search_setup_results_list (void);
-static gboolean action_search_search_dialog (void);
-static gboolean action_search_is_action_match (GtkAction *action,
- const gchar* keyword);
-static void action_search_add_to_results_list (const gchar *label,
- const gchar *tooltip,
- GtkAction* action);
-static void action_search_search_history_and_actions (const gchar *keyword);
-
-static void action_search_update_history (GtkAction *action);
-static void action_search_read_history (void);
-static void action_search_fill_history (void);
-static void action_search_clear_history (void);
-
-static void action_search_preferences_dialog (void);
-static void action_search_set_default_preferences (void);
-static void action_search_update_preferences (void);
-static void action_search_write_preferences (void);
-static void action_search_read_preferences (void);
-static void action_search_set_prefereces_ui_values (void);
-
-gboolean action_search_initializer (void);
-void action_search_finalizer (void);
-static void action_search_context_menu (void);
-
-static GtkWidget * action_search_dialog;
-static GtkWidget * results_list;
-static GtkWidget * keyword_entry;
-
-static gchar *history_file_path;
-static gchar *preference_file_path;
-static gint cur_no_of_his_actions;
-static gboolean first_time = TRUE;
-static gint tmp_x, tmp_y;
-static gint par_x, par_y;
-static gint par_height, par_width;
-
-enum RES_COL {
+typedef struct
+{
+ GtkWidget *dialog;
+
+ GimpGuiConfig *config;
+ GtkWidget *keyword_entry;
+ GtkWidget *results_list;
+ GtkWidget *list_view;
+} SearchDialog;
+
+static void key_released (GtkWidget *widget,
+ GdkEventKey *event,
+ SearchDialog *private);
+static gboolean result_selected (GtkWidget *widget,
+ GdkEventKey *pKey,
+ SearchDialog *private);
+static void row_activated (GtkTreeView *treeview,
+ GtkTreePath *path,
+ GtkTreeViewColumn *col,
+ SearchDialog *private);
+static gboolean action_search_view_accel_find_func (GtkAccelKey *key,
+ GClosure *closure,
+ gpointer data);
+static gchar* action_search_find_accel_label (GtkAction *action);
+static void action_search_add_to_results_list (GtkAction *action,
+ SearchDialog *private);
+static void action_search_run_selected (SearchDialog *private);
+static void action_search_history_and_actions (const gchar *keyword,
+ SearchDialog *private);
+static gboolean action_fuzzy_match (gchar *string,
+ gchar *key);
+static gboolean action_search_match_keyword (GtkAction *action,
+ const gchar* keyword);
+static void action_search_update_position (SearchDialog *private);
+
+static void action_search_finalizer (SearchDialog *private);
+static gboolean quit_button_clicked (GtkWidget *widget,
+ GdkEvent *event,
+ SearchDialog *private );
+static void size_allocated (GtkWidget *widget,
+ GdkRectangle *rec,
+ SearchDialog *private);
+
+static void action_search_setup_results_list (GtkWidget **results_list,
+ GtkWidget **list_view);
+static void search_dialog_free (SearchDialog *private);
+
+enum ResultColumns {
RESULT_ICON,
RESULT_DATA,
RESULT_ACTION,
@@ -86,176 +96,138 @@ enum RES_COL {
N_COL
};
-static struct HISTORY {
- GtkAction *history_action;
- gint count;
-} history[MAX_HISTORY_ACTIONS];
-
-static struct HISTORY_ACTION_NAME {
- char *action_name;
- gint no;
-} name[MAX_HISTORY_ACTIONS];
-
-static struct PREFERENCES {
- gint POSITION;
- gfloat POSITION_X;
- gfloat POSITION_Y;
- gint NO_OF_RESULTS;
- gfloat WIDTH;
- gboolean SHOW_INSENSITIVE;
- gdouble OPACITY;
-} PREF;
-
-static struct ACTION_SEARCH_PREF_UI {
- GtkWidget *specify_radio;
- GtkWidget *pos_x_hbox;
- GtkWidget *pos_y_hbox;
- GtkWidget *right_top_radio;
- GtkWidget *middle_radio;
- GtkWidget *pos_x_spin_button;
- GtkWidget *pos_y_spin_button;
- GtkWidget *no_of_results_spin_button;
- GtkWidget *width_spin_button;
- GtkWidget *opacity_spin_button;
- GtkWidget *show_insensitive_check_button;
-} PREF_UI;
+/* Public Functions */
GtkWidget *
-action_search_dialog_create (void)
+action_search_dialog_create (Gimp *gimp)
{
- if (! action_search_initializer ())
- g_message ("Tito action_search_initializer failed");
+ GtkWidget *action_search_dialog;
+ SearchDialog *private;
+ GimpGuiConfig *config;
+ GtkWidget *main_vbox, *main_hbox;
+ GtkWidget *quit_button;
- action_search_search_dialog ();
- return action_search_dialog;
-}
+ gtk_accel_map_change_entry ("<Actions>/dialogs/dialogs-action-search", 'd', 0, FALSE);
-static void
-modify_position_spins (void)
-{
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (PREF_UI.specify_radio)))
- {
- gtk_widget_set_sensitive (PREF_UI.pos_x_hbox, TRUE);
- gtk_widget_set_sensitive (PREF_UI.pos_y_hbox, TRUE);
- }
- else
- {
- gtk_widget_set_sensitive (PREF_UI.pos_x_hbox, FALSE);
- gtk_widget_set_sensitive (PREF_UI.pos_y_hbox, FALSE);
- }
- gtk_spin_button_set_value (GTK_SPIN_BUTTON (PREF_UI.pos_x_spin_button),
- (gdouble) (PREF.POSITION_X/par_width * 100));
- gtk_spin_button_set_value (GTK_SPIN_BUTTON (PREF_UI.pos_y_spin_button),
- (gdouble) (PREF.POSITION_Y/par_height * 100));
- gtk_spin_button_set_range (GTK_SPIN_BUTTON (PREF_UI.pos_x_spin_button),
- (gdouble) 0,
- (gdouble) (100 - gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON
(PREF_UI.width_spin_button))));
-}
+ config = GIMP_GUI_CONFIG (gimp->config);
-static void
-action_search_clear_history_button_clicked (GtkButton *button,
- gpointer user_data)
-{
- action_search_clear_history ();
-}
+ action_search_dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-static void
-restore_defaults_button_clicked (GtkButton *button,
- gpointer user_data)
-{
- action_search_set_default_preferences ();
- action_search_set_prefereces_ui_values ();
-}
+ private = g_slice_new0 (SearchDialog);
-static void
-action_search_set_prefereces_ui_values (void)
-{
- if (PREF.POSITION == 0)
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (PREF_UI.right_top_radio), TRUE);
- else if (PREF.POSITION == 1)
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (PREF_UI.middle_radio), TRUE);
- else
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (PREF_UI.specify_radio), TRUE);
+ private->dialog = action_search_dialog;
+ private->config = config;
- modify_position_spins ();
+ g_object_weak_ref (G_OBJECT (action_search_dialog),
+ (GWeakNotify) search_dialog_free, private);
- gtk_spin_button_set_value (GTK_SPIN_BUTTON (PREF_UI.no_of_results_spin_button), (gdouble)
PREF.NO_OF_RESULTS);
- gtk_spin_button_set_value (GTK_SPIN_BUTTON (PREF_UI.width_spin_button), (gdouble) PREF.WIDTH);
- gtk_spin_button_set_value (GTK_SPIN_BUTTON (PREF_UI.opacity_spin_button), (gdouble) PREF.OPACITY * 100);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (PREF_UI.show_insensitive_check_button),
PREF.SHOW_INSENSITIVE);
+ gtk_window_set_title (GTK_WINDOW (action_search_dialog), _("Search Actions"));
+ action_search_update_position (private);
+ gtk_window_set_opacity (GTK_WINDOW (action_search_dialog), (gdouble) config->search_dialog_opacity /
100.0);
+ gtk_window_set_keep_above (GTK_WINDOW (action_search_dialog), TRUE);
-}
+ main_vbox = gtk_vbox_new (FALSE, 2);
+ gtk_container_add (GTK_CONTAINER (action_search_dialog), main_vbox);
+ gtk_widget_show (main_vbox);
-static gboolean
-on_focus_out (GtkWidget *widget,
- GdkEventFocus *event,
- gpointer data)
-{
- if (! gtk_widget_is_focus (GTK_WIDGET (data)))
- action_search_finalizer ();
+ main_hbox = gtk_hbox_new (FALSE, 2);
+ gtk_box_pack_start (GTK_BOX (main_vbox), main_hbox, FALSE, TRUE, 0);
+ gtk_widget_show (main_hbox);
- return TRUE;
+ private->keyword_entry = gtk_entry_new ();
+ gtk_entry_set_icon_from_stock (GTK_ENTRY (private->keyword_entry), GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_FIND);
+ gtk_widget_show (private->keyword_entry);
+ gtk_box_pack_start (GTK_BOX (main_hbox), private->keyword_entry, TRUE, TRUE, 0);
+
+ quit_button = gtk_button_new ();
+ gtk_button_set_image (GTK_BUTTON (quit_button),
+ gtk_image_new_from_stock (GTK_STOCK_QUIT,
+ GTK_ICON_SIZE_MENU));
+ gtk_button_set_focus_on_click (GTK_BUTTON (quit_button), FALSE);
+ gtk_widget_set_events (quit_button, GDK_BUTTON_PRESS_MASK);
+ gtk_box_pack_end (GTK_BOX (main_hbox), quit_button, FALSE, TRUE, 0);
+ gtk_widget_show (quit_button);
+
+ action_search_setup_results_list (&private->results_list, &private->list_view);
+ gtk_box_pack_start (GTK_BOX (main_vbox), private->list_view, TRUE, TRUE, 0);
+
+ gtk_widget_set_events (action_search_dialog, GDK_KEY_RELEASE_MASK);
+ gtk_widget_set_events (action_search_dialog, GDK_KEY_PRESS_MASK);
+ gtk_widget_set_events (action_search_dialog, GDK_BUTTON_PRESS_MASK);
+
+ g_signal_connect (private->results_list, "row-activated", (GCallback) row_activated, private);
+ g_signal_connect (private->keyword_entry, "key-release-event", G_CALLBACK (key_released), private);
+ g_signal_connect (private->results_list, "key_press_event", G_CALLBACK (result_selected), private);
+ g_signal_connect (quit_button, "clicked", G_CALLBACK (quit_button_clicked), private);
+ g_signal_connect (action_search_dialog, "size-allocate", G_CALLBACK (size_allocated), private);
+
+ gtk_widget_show (action_search_dialog);
+
+ return action_search_dialog;
}
+/* Private Functions */
static void
-key_released (GtkWidget *widget,
- GdkEventKey *event,
- gpointer func_data)
+key_released (GtkWidget *widget,
+ GdkEventKey *event,
+ SearchDialog *private)
{
- const gchar *entry_text;
- GtkWidget *list_view = GTK_WIDGET (func_data);
+ gchar *entry_text;
+ gint width;
+ gtk_window_get_size (GTK_WINDOW (private->dialog), &width, NULL);
entry_text = gtk_editable_get_chars (GTK_EDITABLE (widget), 0, -1);
switch (event->keyval)
{
case GDK_Escape:
{
- action_search_finalizer ();
+ action_search_finalizer (private);
return;
}
case GDK_Return:
{
- action_search_run_result_action ();
+ action_search_run_selected (private);
return;
}
}
if (strcmp (entry_text, "") != 0)
{
- gtk_window_resize (GTK_WINDOW (action_search_dialog), (PREF.WIDTH * par_width) / 100,
- PREF.NO_OF_RESULTS * 40 + 100);
- gtk_list_store_clear (GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (results_list))));
- gtk_widget_show_all (list_view);
- action_search_search_history_and_actions (entry_text);
- gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (results_list)),
+ gtk_window_resize (GTK_WINDOW (private->dialog), width,
+ private->config->search_dialog_height);
+ gtk_list_store_clear (GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW
(private->results_list))));
+ gtk_widget_show_all (private->list_view);
+ action_search_history_and_actions (entry_text, private);
+ gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (private->results_list)),
gtk_tree_path_new_from_string ("0"));
}
else if (strcmp (entry_text, "") == 0 && (event->keyval == GDK_Down) )
{
- gtk_window_resize (GTK_WINDOW (action_search_dialog), (PREF.WIDTH * par_width) / 100,
- PREF.NO_OF_RESULTS * 40 + 100);
- gtk_list_store_clear (GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (results_list))));
- gtk_widget_show_all (list_view);
- action_search_search_history_and_actions (" ");
- gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (results_list)),
+ gtk_window_resize (GTK_WINDOW (private->dialog), width,
+ private->config->search_dialog_height);
+ gtk_list_store_clear (GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW
(private->results_list))));
+ gtk_widget_show_all (private->list_view);
+ action_search_history_and_actions (" ", private);
+ gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (private->results_list)),
gtk_tree_path_new_from_string ("0"));
}
else
{
- gtk_widget_hide (list_view);
- gtk_window_resize (GTK_WINDOW (action_search_dialog),
- (PREF.WIDTH * par_width) / 100,
- DEFAULT_HEIGHT);
+ gtk_widget_hide (private->list_view);
+ gtk_window_resize (GTK_WINDOW (private->dialog),
+ width, 1);
}
+
+ g_free (entry_text);
}
static gboolean
-result_selected (GtkWidget *widget,
- GdkEventKey *pKey,
- gpointer func_data)
+result_selected (GtkWidget *widget,
+ GdkEventKey *pKey,
+ SearchDialog *private)
{
if (pKey->type == GDK_KEY_PRESS)
{
@@ -263,12 +235,12 @@ result_selected (GtkWidget *widget,
{
case GDK_Return:
{
- action_search_run_result_action ();
+ action_search_run_selected (private);
break;
}
case GDK_Escape:
{
- action_search_finalizer ();
+ action_search_finalizer (private);
return TRUE;
}
case GDK_Up:
@@ -278,7 +250,7 @@ result_selected (GtkWidget *widget,
GtkTreePath *path;
GtkTreeIter iter;
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (results_list));
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (private->results_list));
gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
if (gtk_tree_selection_get_selected (selection, &model, &iter))
@@ -287,36 +259,36 @@ result_selected (GtkWidget *widget,
if (strcmp (gtk_tree_path_to_string (path), "0") == 0)
{
- gtk_widget_grab_focus ((GTK_WIDGET (keyword_entry)));
+ gtk_widget_grab_focus ((GTK_WIDGET (private->keyword_entry)));
return TRUE;
}
}
}
}
}
+
return FALSE;
}
-
static void
row_activated (GtkTreeView *treeview,
GtkTreePath *path,
GtkTreeViewColumn *col,
- gpointer userdata)
+ SearchDialog *private)
{
- action_search_run_result_action ();
+ action_search_run_selected (private);
}
static gboolean
-action_search_action_view_accel_find_func (GtkAccelKey *key,
- GClosure *closure,
- gpointer data)
+action_search_view_accel_find_func (GtkAccelKey *key,
+ GClosure *closure,
+ gpointer data)
{
return (GClosure *) data == closure;
}
static gchar*
-find_accel_label (GtkAction *action)
+action_search_find_accel_label (GtkAction *action)
{
guint accel_key = 0;
GdkModifierType accel_mask = 0;
@@ -332,8 +304,9 @@ find_accel_label (GtkAction *action)
if (accel_closure)
{
GtkAccelKey *key;
+
key = gtk_accel_group_find (accel_group,
- action_search_action_view_accel_find_func,
+ action_search_view_accel_find_func,
accel_closure);
if (key &&
key->accel_key &&
@@ -346,27 +319,29 @@ find_accel_label (GtkAction *action)
accel_string = gtk_accelerator_get_label (accel_key, accel_mask);
- return (strcmp (accel_string, "") == 0)? accel_string : NULL;
-}
+ if (strcmp (accel_string, "") == 0)
+ {
+ /* The value returned by gtk_accelerator_get_label() must be freed after use. */
+ g_free (accel_string);
+ accel_string = NULL;
+ }
+ return accel_string;
+}
static void
-action_search_add_to_results_list (const gchar *label,
- const gchar *tooltip,
- GtkAction *action)
+action_search_add_to_results_list (GtkAction *action,
+ SearchDialog *private)
{
GtkTreeIter iter;
GtkListStore *store;
gchar *markuptxt;
- gchar *accel_string = find_accel_label (action);
- const gchar *stock_id = gtk_action_get_stock_id (action);
- char *data = g_new (char, 1024);
- char shortcut[1024] = "";
-
- if (data == NULL ||
- strchr (label, '@') != NULL ||
- strchr (label, '&') != NULL)
- return;
+ gchar *label = gimp_strip_uline (gtk_action_get_label (action));
+ const gchar *stock_id = gtk_action_get_stock_id (action);
+ gchar *accel_string = action_search_find_accel_label (action);
+ gboolean has_shortcut = FALSE;
+ const gchar *tooltip = gtk_action_get_tooltip (action);
+ gboolean has_tooltip = FALSE;
if (GTK_IS_TOGGLE_ACTION (action))
{
@@ -376,29 +351,20 @@ action_search_add_to_results_list (const gchar *label,
stock_id = GTK_STOCK_NO;
}
- if (accel_string == NULL)
- strcpy (shortcut, "");
- else if (strchr (accel_string, '<') != NULL)
- strcpy (shortcut, "");
- else
- {
- strcpy (shortcut, " | ");
- strcat (shortcut, accel_string);
- }
+ if (accel_string != NULL && strchr (accel_string, '<') == NULL)
+ has_shortcut = TRUE;
- if (tooltip == NULL)
- strcpy (data, "");
- else if (strchr (tooltip, '<') != NULL)
- strcpy (data, "");
- else
- {
- strcpy (data, "\n");
- strcat (data, tooltip);
- }
+ if (tooltip != NULL && strchr (tooltip, '<') == NULL)
+ has_tooltip = TRUE;
+
+ markuptxt = g_strdup_printf ("%s<small>%s%s%s<span weight='light'>%s</span></small>",
+ label,
+ has_shortcut ? " | " : "",
+ has_shortcut ? accel_string : "",
+ has_tooltip ? "\n" : "",
+ has_tooltip ? tooltip : "");
- markuptxt = g_strdup_printf ("%s<small>%s<span weight='light'>%s</span></small>",
- label, shortcut, data);
- store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (results_list)));
+ store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (private->results_list)));
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
RESULT_ICON, stock_id,
@@ -406,18 +372,22 @@ action_search_add_to_results_list (const gchar *label,
RESULT_ACTION, action,
IS_SENSITIVE, gtk_action_get_sensitive (action),
-1);
- g_free (data);
+
+ g_free (accel_string);
+ g_free (markuptxt);
+ g_free (label);
}
-gboolean
-action_search_run_result_action (void)
+static void
+action_search_run_selected (SearchDialog *private)
{
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter;
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (results_list));
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (private->results_list));
gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+
if (gtk_tree_selection_get_selected (selection, &model, &iter))
{
GtkAction *action;
@@ -425,719 +395,311 @@ action_search_run_result_action (void)
gtk_tree_model_get (model, &iter, RESULT_ACTION, &action, -1);
if (! gtk_action_get_sensitive (action))
- return FALSE;
+ return;
- gtk_widget_hide (action_search_dialog);
gtk_action_activate (action);
- action_search_finalizer ();
- action_search_update_history (action);
+ action_search_finalizer (private);
}
- return TRUE;
+ return;
}
-
-void
-action_search_search_history_and_actions (const gchar *keyword)
+static void
+action_search_history_and_actions (const gchar *keyword,
+ SearchDialog *private)
{
GList *list;
GimpUIManager *manager;
- gint i = 0;
+ GList *history_actions = NULL;
manager = gimp_ui_managers_from_name ("<Image>")->data;
if (strcmp (keyword, "") == 0)
return;
- for (i = 0;i<cur_no_of_his_actions;i++)
- {
- if (history[i].history_action != NULL)
- {
- if (action_search_is_action_match (history[i].history_action, keyword))
- action_search_add_to_results_list (gimp_strip_uline (gtk_action_get_label
(history[i].history_action)),
- gtk_action_get_tooltip (history[i].history_action),
- history[i].history_action );
- }
- }
+ history_actions = gimp_action_history_search (keyword,
+ action_search_match_keyword,
+ private->config);
+ /* First put on top of the list any matching action of user history. */
+ for (list = history_actions; list; list = g_list_next (list))
+ {
+ action_search_add_to_results_list (GTK_ACTION (list->data), private);
+ }
+
+ /* Now check other actions. */
for (list = gtk_ui_manager_get_action_groups (GTK_UI_MANAGER (manager));
list;
list = g_list_next (list))
{
- GimpActionGroup *group = list->data;
- GList *actions;
GList *list2;
-
+ GimpActionGroup *group = list->data;
+ GList *actions = NULL;
actions = gtk_action_group_list_actions (GTK_ACTION_GROUP (group));
actions = g_list_sort (actions, (GCompareFunc) gimp_action_name_compare);
for (list2 = actions; list2; list2 = g_list_next (list2))
{
- GtkAction *action = list2->data;
- const gchar *name;
- gboolean is_redundant = FALSE;
- name = gtk_action_get_name (action);
+ GList *list3;
+ const gchar *name;
+ GtkAction *action = list2->data;
+ gboolean is_redundant = FALSE;
+ name = gtk_action_get_name (action);
- if (strstr (name, "-menu") ||
- strstr (name, "-popup") ||
- strstr (name, "context") ||
- strstr (name, "edit-undo") ||
+ if (g_str_has_suffix (name, "-menu") ||
+ g_str_has_suffix (name, "-popup") ||
+ g_str_has_prefix (name, "context-") ||
name[0] == '<')
continue;
- if (! gtk_action_get_sensitive (action) && ! (PREF.SHOW_INSENSITIVE) )
- continue;
+ if (! gtk_action_get_sensitive (action) && ! private->config->search_show_unavailable)
+ continue;
- for (i = 0;i<cur_no_of_his_actions;i++)
+ if (action_search_match_keyword (action, keyword))
{
- if (history[i].history_action != NULL)
+ /* A matching action. Check if we have not already added it as an history action. */
+ for (list3 = history_actions; list3; list3 = g_list_next (list3))
{
- if (strcmp (gtk_action_get_name (history[i].history_action), name) == 0)
+ if (strcmp (gtk_action_get_name (GTK_ACTION (list3->data)), name) == 0)
{
is_redundant = TRUE;
break;
}
}
- }
-
- if (is_redundant)
- continue;
- if (action_search_is_action_match (action, keyword))
- {
- action_search_add_to_results_list (gimp_strip_uline (gtk_action_get_label (action)),
- gtk_action_get_tooltip (action),
- action);
+ if (! is_redundant)
+ action_search_add_to_results_list (action, private);
}
}
+
g_list_free (actions);
}
-}
-static void action_search_fill_history (void)
-{
- GList *list;
- GimpUIManager *manager;
- gint i = 0;
- manager = gimp_ui_managers_from_name ("<Image>")->data;
-
- for (list = gtk_ui_manager_get_action_groups (GTK_UI_MANAGER (manager));
- list;
- list = g_list_next (list))
- {
- GimpActionGroup *group = list->data;
- GList *actions;
- GList *list2;
-
- actions = gtk_action_group_list_actions (GTK_ACTION_GROUP (group));
- actions = g_list_sort (actions, (GCompareFunc) gimp_action_name_compare);
-
- for (list2 = actions; list2; list2 = g_list_next (list2))
- {
- GtkAction *action = list2->data;
- const gchar *action_name;
- action_name = gtk_action_get_name (action);
-
- if (strstr (action_name, "-menu") ||
- strstr (action_name, "-popup") ||
- strstr (action_name, "context") ||
- action_name[0] == '<')
- continue;
-
- for (i = 0;i<cur_no_of_his_actions;i++)
- {
- if (name[i].action_name != NULL)
- {
- if (strcmp (name[i].action_name, action_name) == 0)
- {
- history[i].history_action = action;
- history[i].count = name[i].no;
- }
- }
- }
- }
- }
+ g_list_free_full (history_actions, (GDestroyNotify) g_object_unref);
}
+/* Fuzzy search matching.
+ @return TRUE if all the letters of `key` are found in `string`,
+ in the same order (even with intermediate letters). */
static gboolean
-fuzzy_search (gchar *string,
- gchar *key)
+action_fuzzy_match (gchar *string,
+ gchar *key)
{
gchar *remaining_string = string;
+
if (strlen (key) == 0 )
- return TRUE;
+ return TRUE;
if ((remaining_string = strchr (string, key[0])) != NULL )
- return fuzzy_search (remaining_string+1, key+1 );
+ return action_fuzzy_match (remaining_string + 1,
+ key + 1);
else
return FALSE;
}
static gboolean
-action_search_is_action_match (GtkAction *action,
- const gchar* keyword)
+action_search_match_keyword (GtkAction *action,
+ const gchar* keyword)
{
- gchar *label, *tooltip, *key;
- gint i;
- gchar* space_pos;
- label = g_new (gchar, 1024);
- key = g_new (gchar, 1024);
- tooltip = g_new (gchar, 1024);
+ gboolean matched = FALSE;
+ gchar *key = g_strdup (keyword);
+ gchar *label;
+ gint i;
- strcpy (label, gimp_strip_uline (gtk_action_get_label (action)));
- strcpy (key, keyword);
+ label = gimp_strip_uline (gtk_action_get_label (action));
- for (i = 0;i<strlen (label);i++)
+ for (i = 0 ; i < strlen (label); i++)
label[i] = tolower (label[i]);
- for (i = 0;i<strlen (key);i++)
+ for (i = 0; i < strlen (key); i++)
key[i] = tolower (key[i]);
+
+ /* If keyword is two characters,
+ then match them with first letters of first and second word in the labels.
+ For instance 'gb' will list 'Gaussian Blur...' */
if (strlen (key) == 2)
{
+ gchar* space_pos;
+
space_pos = strchr (label, ' ');
- if (space_pos!= NULL)
+
+ if (space_pos != NULL)
{
space_pos++;
+
if (key[0] == label[0] && key[1] == *space_pos)
- return TRUE;
+ matched = TRUE;
}
}
- if (strstr (label, key))
- return TRUE;
-
- if (fuzzy_search (label, key))
- return TRUE;
-
- if (strlen (key)>2 || strcmp (key, " ") == 0)
+ if (! matched)
{
- if (gtk_action_get_tooltip (action)!= NULL)
+ if (strstr (label, key) || action_fuzzy_match (label, key))
{
- strcpy (tooltip, gtk_action_get_tooltip (action));
- for (i = 0;i<strlen (tooltip);i++)
- tooltip[i] = tolower (tooltip[i]);
+ matched = TRUE;
+ }
+ else if (strlen (key) > 2 || strcmp (key, " ") == 0)
+ {
+ if (gtk_action_get_tooltip (action)!= NULL)
+ {
+ gchar *tooltip = g_strdup (gtk_action_get_tooltip (action));
+
+ for (i = 0; i < strlen (tooltip); i++)
+ tooltip[i] = tolower (tooltip[i]);
- if (strstr (tooltip, key))
- return TRUE;
+ if (strstr (tooltip, key))
+ matched = TRUE;
+
+ g_free (tooltip);
+ }
}
}
g_free (label);
g_free (key);
- g_free (tooltip);
- return FALSE;
+ return matched;
}
static void
-action_search_read_history (void)
+action_search_update_position (SearchDialog *private)
{
- gint i;
- FILE *fp;
- cur_no_of_his_actions = 0;
+ GimpGuiConfig *config = private->config;
+ GtkWidget *dialog = private->dialog;
+ gint parent_height, parent_width;
+ gint parent_x, parent_y;
+ gint screen_width, screen_height;
+ GdkScreen *screen = gdk_screen_get_default ();
+ GdkWindow *par_window = gdk_screen_get_active_window (screen);
- fp = fopen (history_file_path, "r");
- if (fp == NULL)
- return;
+ screen_width = gdk_screen_get_width (screen);
+ screen_height = gdk_screen_get_height (screen);
+ gdk_window_get_geometry (par_window, &parent_x, &parent_y, &parent_width, &parent_height, NULL);
- for (i = 0;i<MAX_HISTORY_ACTIONS;i++)
+ if (config->search_dialog_width == -1)
{
- if (fscanf (fp, "%s %d", name[i].action_name, &name[i].no) == EOF)
- break;
- cur_no_of_his_actions++;
+ config->search_dialog_width = parent_width / 2;
}
-
- fclose (fp);
- action_search_fill_history ();
-}
-
-static gint
-compare (const void * a,
- const void * b)
-{
- struct HISTORY *p = (struct HISTORY *)a;
- struct HISTORY *q = (struct HISTORY *)b;
- return (q->count - p->count);
-}
-
-static void
-action_search_update_history (GtkAction *action)
-{
- gint i;
- FILE *fp;
- gboolean is_present = FALSE;
-
- fp = fopen (history_file_path, "w");
- if (fp == NULL)
+ else if (config->search_dialog_width > parent_width)
{
- g_message ("Unable to open history file to write");
- return;
+ config->search_dialog_width = parent_width;
}
-
- for (i = 0;i<cur_no_of_his_actions;i++)
+ if (config->search_dialog_height == -1)
{
- if (strcmp (gtk_action_get_name (action), gtk_action_get_name (history[i].history_action)) == 0)
- {
- history[i].count++;
- is_present = TRUE;
- break;
- }
+ config->search_dialog_height = parent_height / 2;
}
-
- if (! is_present)
+ else if (config->search_dialog_height > parent_height)
{
- if (cur_no_of_his_actions == MAX_HISTORY_ACTIONS)
- {
- history[MAX_HISTORY_ACTIONS-1].history_action = action;
- history[MAX_HISTORY_ACTIONS-1].count = 1;
- }
- else
- {
- history[cur_no_of_his_actions].history_action = action;
- history[cur_no_of_his_actions++].count = 1;
- }
+ config->search_dialog_height = parent_height;
}
- qsort (history, cur_no_of_his_actions, sizeof (struct HISTORY), compare);
-
- for (i = 0;i<cur_no_of_his_actions;i++)
+ if (config->search_dialog_x < 0 || config->search_dialog_x + config->search_dialog_width > screen_width)
{
- if (history[i].history_action != NULL)
- fprintf (fp, "%s %d \n", gtk_action_get_name (history[i].history_action),
- history[i].count);
+ config->search_dialog_x = parent_x + (parent_width - config->search_dialog_width) / 2;
+ }
+ if (config->search_dialog_y == -1 || config->search_dialog_y + config->search_dialog_height >
screen_height)
+ {
+ config->search_dialog_y = parent_y + (parent_height - config->search_dialog_height) / 2 ;
}
- fclose (fp);
-}
-
-static void
-action_search_update_position (void)
-{
- if (PREF.POSITION == 0)
- {
- PREF.POSITION_X = (1-PREF.WIDTH/100)*par_width+par_x;
- PREF.POSITION_Y = 0.04*par_height+par_y;
- }
- else if (PREF.POSITION == 1)
- {
- PREF.POSITION_X = (par_width- PREF.WIDTH*par_width*.01)/2 + par_x;
- PREF.POSITION_Y = 0.2*par_height + par_y;
- }
- else
- {
- PREF.POSITION_X = tmp_x*par_width/100 + par_x;
- PREF.POSITION_Y = tmp_y*par_height/100 + par_y;
- }
- gtk_window_move (GTK_WINDOW (action_search_dialog), PREF.POSITION_X, PREF.POSITION_Y);
+ gtk_window_set_default_size (GTK_WINDOW (dialog),
+ config->search_dialog_width,
+ 1);
+ gtk_window_move (GTK_WINDOW (dialog),
+ config->search_dialog_x, config->search_dialog_y);
}
void
-action_search_finalizer (void)
-{
- gtk_widget_destroy (action_search_dialog);
-}
-
-static void
-initialize_storage (void)
+action_search_finalizer (SearchDialog *private)
{
- gchar *dir_filename = g_build_filename (gimp_directory (), "tito", NULL);
+ gint x, y, width, height;
+ GimpGuiConfig *config = private->config;
- g_mkdir (dir_filename,
- S_IRUSR | S_IWUSR | S_IXUSR |
- S_IRGRP | S_IXGRP |
- S_IROTH | S_IXOTH);
+ gtk_window_get_size (GTK_WINDOW (private->dialog), &width, &height);
+ gtk_window_get_position (GTK_WINDOW (private->dialog), &x, &y);
- history_file_path = g_new (gchar, 1024);
- strcpy (history_file_path, dir_filename);
-
- preference_file_path = g_new (gchar, 1024);
- strcpy (preference_file_path, dir_filename);
-
- strcat (history_file_path, "/history");
- strcat (preference_file_path, "/preferences");
-
- g_free (dir_filename);
-}
-
-gboolean
-action_search_initializer (void)
-{
- gint i = 0;
- GdkWindow *par_window = gdk_screen_get_active_window (gdk_screen_get_default ());
-
- gdk_window_get_geometry (par_window, &par_x, &par_y, &par_width, &par_height, NULL);
-
- if (first_time)
- {
- initialize_storage ();
-
- for (i = 0;i<MAX_HISTORY_ACTIONS;i++)
- {
- name[i].action_name = g_new (char, 100);
- strcpy (name[i].action_name, "");
- name[i].no = 0;
- }
- first_time = FALSE;
- }
- action_search_read_preferences ();
- action_search_read_history ();
- gtk_accel_map_change_entry ("<Actions>/dialogs/dialogs-action-search", 'd', 0, FALSE);
- return TRUE;
-}
-
-static void
-action_search_clear_history (void)
-{
- FILE *fp;
- fp = fopen (history_file_path, "w");
- if (fp == NULL)
+ if (x < 0)
{
- g_message ("file not created");
- return;
+ x = 0;
}
- fclose (fp);
-}
-
-static void
-action_search_set_default_preferences (void)
-{
- PREF.POSITION = 1;
- PREF.WIDTH = 40;
- PREF.POSITION_X = (1-0.4)*par_width+par_x;
- PREF.POSITION_Y = 0.04*par_height+par_y;
- PREF.NO_OF_RESULTS = 4;
- PREF.SHOW_INSENSITIVE = FALSE;
- PREF.OPACITY = 1;
- action_search_write_preferences ();
-}
-
-static void
-action_search_update_preferences (void)
-{
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (PREF_UI.right_top_radio)))
- PREF.POSITION = 0;
- else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (PREF_UI.middle_radio)))
- PREF.POSITION = 1;
- else
+ if (y < 0)
{
- PREF.POSITION = 2;
- tmp_x = (gfloat) gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (PREF_UI.pos_x_spin_button));
- tmp_y = (gfloat) gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (PREF_UI.pos_y_spin_button));
+ y = 0;
}
+ config->search_dialog_x = x;
+ config->search_dialog_y = y;
- PREF.NO_OF_RESULTS = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON
(PREF_UI.no_of_results_spin_button));
- PREF.WIDTH = (gfloat)gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON
(PREF_UI.width_spin_button));
- PREF.OPACITY = (gdouble)gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON
(PREF_UI.opacity_spin_button))/100;
- PREF.SHOW_INSENSITIVE = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
(PREF_UI.show_insensitive_check_button));
-
- action_search_update_position ();
- action_search_write_preferences ();
- action_search_finalizer ();
-}
-
-static void
-action_search_write_preferences (void)
-{
- FILE *fp;
- fp = fopen (preference_file_path, "w");
-
- if (fp == NULL)
- {
- g_message ("Unable to open preferences file to write");
- return;
- }
-
- if (fp == NULL)
- return;
- fprintf (fp, "%d %f %f %d %f %d %lf", PREF.POSITION, PREF.POSITION_X, PREF.POSITION_Y,
- PREF.NO_OF_RESULTS, PREF.WIDTH, PREF.SHOW_INSENSITIVE, PREF.OPACITY);
- fclose (fp);
-}
-
-static void
-action_search_read_preferences (void)
-{
- FILE *fp;
-
- fp = fopen (preference_file_path, "r");
-
- if (fp == NULL)
- {
- action_search_set_default_preferences ();
- return;
- }
-
- if (fscanf (fp, "%d %f %f %d %f %d %lf",
- &PREF.POSITION, &PREF.POSITION_X, &PREF.POSITION_Y,
- &PREF.NO_OF_RESULTS, &PREF.WIDTH, &PREF.SHOW_INSENSITIVE,
- &PREF.OPACITY) == 0)
- action_search_set_default_preferences ();
-
- fclose (fp);
+ gtk_widget_destroy (private->dialog);
}
static gboolean
-context_menu_invoked (GtkWidget *widget,
- GdkEvent *event,
- gpointer user_data)
+quit_button_clicked (GtkWidget *widget,
+ GdkEvent *event,
+ SearchDialog *private)
{
- action_search_context_menu ();
- return TRUE;
-}
+ action_search_finalizer (private);
-static void
-context_menu_handler (GtkMenuItem* menuitem,
- gpointer *data)
-{
- if (strchr (gtk_menu_item_get_label (menuitem), 'r') != NULL)
- action_search_preferences_dialog ();
- else
- gtk_widget_destroy (action_search_dialog);
+ return TRUE;
}
static void
-action_search_context_menu (void)
+size_allocated (GtkWidget *widget,
+ GdkRectangle *rec,
+ SearchDialog *private)
{
- GtkWidget *preferences_menuitem;
- GtkWidget *close_menuitem;
- GtkWidget *context_menu;
+ private->config->search_dialog_width = rec->width;
- context_menu = gtk_menu_new ();
- preferences_menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_PREFERENCES, NULL);
- close_menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_CLOSE, NULL);
-
- gtk_menu_shell_append (GTK_MENU_SHELL (context_menu), preferences_menuitem);
- gtk_menu_shell_append (GTK_MENU_SHELL (context_menu), close_menuitem);
-
- gtk_widget_show (context_menu);
- gtk_widget_show (preferences_menuitem);
- gtk_widget_show (close_menuitem);
-
- g_signal_connect (preferences_menuitem, "activate", G_CALLBACK (context_menu_handler), NULL);
- g_signal_connect (close_menuitem, "activate", G_CALLBACK (context_menu_handler), NULL);
-
- gtk_menu_popup (GTK_MENU (context_menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time ());
+ if (gtk_widget_get_visible (private->list_view))
+ {
+ private->config->search_dialog_height = rec->height;
+ }
}
static void
-action_search_preferences_dialog (void)
-{
- GtkWidget *pref_dialog;
- GtkWidget *top_hbox;
-
- GtkWidget *position_frame;
- GtkWidget *position_vbox;
- GtkWidget *pos_x_label;
- GtkWidget *pos_y_label;
- GtkWidget *specify_alignment_x;
- GtkWidget *specify_alignment_y;
-
- GtkWidget *display_frame;
- GtkWidget *display_vbox;
- GtkWidget *no_of_results_hbox;
- GtkWidget *width_hbox;
- GtkWidget *opacity_hbox;
- GtkWidget *no_of_results_label;
- GtkWidget *width_label;
- GtkWidget *opacity_label;
-
- GtkWidget *bottom_hbox;
- GtkWidget *action_search_clear_history_button;
- GtkWidget *restore_defaults_button;
-
- pref_dialog = gtk_dialog_new_with_buttons ("Tito preferences",
- NULL,
- GTK_DIALOG_MODAL,
- GTK_STOCK_OK,
- GTK_RESPONSE_ACCEPT,
- GTK_STOCK_CANCEL,
- GTK_RESPONSE_REJECT,
- NULL);
-
- gtk_window_set_position (GTK_WINDOW (pref_dialog), GTK_WIN_POS_CENTER_ALWAYS);
- top_hbox = gtk_hbox_new (FALSE, 10);
- gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (pref_dialog))), top_hbox, FALSE,
FALSE, 2);
-
- position_frame = gtk_frame_new ("Postion");
- position_vbox = gtk_vbox_new (TRUE, 2);
-
- gtk_frame_set_shadow_type (GTK_FRAME (position_frame), GTK_SHADOW_ETCHED_IN);
-
- PREF_UI.right_top_radio = gtk_radio_button_new_with_label (NULL, "Right-Top");
- PREF_UI.middle_radio = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON
(PREF_UI.right_top_radio), "Middle");
- PREF_UI.specify_radio = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON
(PREF_UI.right_top_radio), "Specify");
- PREF_UI.pos_x_hbox = gtk_hbox_new (FALSE, 1);
- PREF_UI.pos_y_hbox = gtk_hbox_new (FALSE, 1);
- specify_alignment_x = gtk_alignment_new (1, 0, 0, 0);
- specify_alignment_y = gtk_alignment_new (1, 0, 0, 0);
- pos_x_label = gtk_label_new ("x:");
- pos_y_label = gtk_label_new ("y:");
- PREF_UI.pos_x_spin_button = gtk_spin_button_new_with_range (0, 100-PREF.WIDTH, 1);
- PREF_UI.pos_y_spin_button = gtk_spin_button_new_with_range (0, 50, 1);
-
- gtk_box_pack_start (GTK_BOX (top_hbox), position_frame, FALSE, FALSE, 2);
- gtk_container_add (GTK_CONTAINER (position_frame), position_vbox);
- gtk_box_pack_start (GTK_BOX (position_vbox), PREF_UI.right_top_radio, TRUE, TRUE, 2);
- gtk_box_pack_start (GTK_BOX (position_vbox), PREF_UI.middle_radio, TRUE, TRUE, 2);
- gtk_box_pack_start (GTK_BOX (position_vbox), PREF_UI.specify_radio, TRUE, TRUE, 2);
-
- gtk_box_pack_start (GTK_BOX (position_vbox), specify_alignment_x, TRUE, TRUE, 1);
- gtk_container_add (GTK_CONTAINER (specify_alignment_x), PREF_UI.pos_x_hbox);
- gtk_box_pack_start (GTK_BOX (PREF_UI.pos_x_hbox), pos_x_label, TRUE, TRUE, 1);
- gtk_box_pack_start (GTK_BOX (PREF_UI.pos_x_hbox), PREF_UI.pos_x_spin_button, TRUE, TRUE, 1);
-
- gtk_box_pack_start (GTK_BOX (position_vbox), specify_alignment_y, TRUE, TRUE, 1);
- gtk_container_add (GTK_CONTAINER (specify_alignment_y), PREF_UI.pos_y_hbox);
- gtk_box_pack_start (GTK_BOX (PREF_UI.pos_y_hbox), pos_y_label, TRUE, TRUE, 1);
- gtk_box_pack_start (GTK_BOX (PREF_UI.pos_y_hbox), PREF_UI.pos_y_spin_button, TRUE, TRUE, 1);
-
- display_frame = gtk_frame_new ("Display");
- display_vbox = gtk_vbox_new (TRUE, 2);
-
- gtk_frame_set_shadow_type (GTK_FRAME (display_frame), GTK_SHADOW_ETCHED_IN);
-
- no_of_results_hbox = gtk_hbox_new (FALSE, 2);
- width_hbox = gtk_hbox_new (FALSE, 2);
- opacity_hbox = gtk_hbox_new (FALSE, 2);
- no_of_results_label = gtk_label_new ("Results height:");
- PREF_UI.no_of_results_spin_button = gtk_spin_button_new_with_range (2, 10, 1);
- width_label = gtk_label_new ("Tito Width:");
- PREF_UI.width_spin_button = gtk_spin_button_new_with_range (20, 60, 1);
- opacity_label = gtk_label_new ("Tito Opacity:");
- PREF_UI.opacity_spin_button = gtk_spin_button_new_with_range (40, 100, 10);
- PREF_UI.show_insensitive_check_button = gtk_check_button_new_with_label ("Show unavailable actions");
- action_search_clear_history_button = gtk_button_new_with_label ("Clear history");
- restore_defaults_button = gtk_button_new_with_label ("Restore defaults");
-
- gtk_box_pack_start (GTK_BOX (top_hbox), display_frame, FALSE, FALSE, 2);
- gtk_container_add (GTK_CONTAINER (display_frame), display_vbox);
- gtk_box_pack_start (GTK_BOX (display_vbox), no_of_results_hbox, TRUE, TRUE, 2);
- gtk_box_pack_start (GTK_BOX (no_of_results_hbox), no_of_results_label, TRUE, TRUE, 2);
- gtk_box_pack_start (GTK_BOX (no_of_results_hbox), PREF_UI.no_of_results_spin_button, TRUE, TRUE, 2);
- gtk_box_pack_start (GTK_BOX (display_vbox), width_hbox, TRUE, TRUE, 2);
- gtk_box_pack_start (GTK_BOX (width_hbox), width_label, TRUE, TRUE, 2);
- gtk_box_pack_start (GTK_BOX (width_hbox), PREF_UI.width_spin_button, TRUE, TRUE, 2);
- gtk_box_pack_start (GTK_BOX (display_vbox), opacity_hbox, TRUE, TRUE, 2);
- gtk_box_pack_start (GTK_BOX (opacity_hbox), opacity_label, TRUE, TRUE, 2);
- gtk_box_pack_start (GTK_BOX (opacity_hbox), PREF_UI.opacity_spin_button, TRUE, TRUE, 2);
- gtk_box_pack_start (GTK_BOX (display_vbox), PREF_UI.show_insensitive_check_button, TRUE, TRUE, 2);
-
- bottom_hbox = gtk_hbox_new (TRUE, 2);
- gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (pref_dialog))), bottom_hbox, FALSE,
FALSE, 2);
- gtk_box_pack_start (GTK_BOX (bottom_hbox), action_search_clear_history_button, TRUE, TRUE, 2);
- gtk_box_pack_start (GTK_BOX (bottom_hbox), restore_defaults_button, TRUE, TRUE, 2);
-
- action_search_set_prefereces_ui_values ();
- gtk_widget_show_all (pref_dialog);
-
- g_signal_connect (PREF_UI.right_top_radio, "toggled", G_CALLBACK (modify_position_spins), NULL);
- g_signal_connect (PREF_UI.middle_radio, "toggled", G_CALLBACK (modify_position_spins), NULL);
- g_signal_connect (PREF_UI.specify_radio, "toggled", G_CALLBACK (modify_position_spins), NULL);
- g_signal_connect (action_search_clear_history_button, "clicked", G_CALLBACK
(action_search_clear_history_button_clicked), NULL);
- g_signal_connect (restore_defaults_button, "clicked", G_CALLBACK (restore_defaults_button_clicked), NULL);
-
- if (gtk_dialog_run (GTK_DIALOG (pref_dialog)) == GTK_RESPONSE_ACCEPT)
- action_search_update_preferences ();
-
- gtk_widget_destroy (pref_dialog);
-}
-
-static GtkWidget*
-action_search_setup_results_list (void)
+action_search_setup_results_list (GtkWidget **results_list,
+ GtkWidget **list_view)
{
gint wid1 = 100;
- GtkWidget *sc_win;
GtkListStore *store;
GtkCellRenderer *cell1;
GtkCellRenderer *cell_renderer;
GtkTreeViewColumn *column1, *column2;
- sc_win = gtk_scrolled_window_new (NULL, NULL);
- store = gtk_list_store_new (N_COL, G_TYPE_STRING, G_TYPE_STRING, GTK_TYPE_ACTION, G_TYPE_BOOLEAN);
- results_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
- gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (results_list), FALSE);
+ *list_view = GTK_WIDGET (gtk_scrolled_window_new (NULL, NULL));
+ store = gtk_list_store_new (N_COL, G_TYPE_STRING, G_TYPE_STRING,
+ GTK_TYPE_ACTION, G_TYPE_BOOLEAN);
+ *results_list = GTK_WIDGET (gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)));
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (*results_list), FALSE);
cell1 = gtk_cell_renderer_pixbuf_new ();
column1 = gtk_tree_view_column_new_with_attributes (NULL,
- cell1,
- "stock_id", RESULT_ICON,
- NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (results_list), column1);
+ cell1,
+ "stock_id", RESULT_ICON,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (*results_list), column1);
gtk_tree_view_column_add_attribute (column1, cell1, "sensitive", IS_SENSITIVE);
gtk_tree_view_column_set_min_width (column1, 22);
cell_renderer = gtk_cell_renderer_text_new ();
column2 = gtk_tree_view_column_new_with_attributes (NULL,
- cell_renderer,
- "markup", RESULT_DATA,
- NULL);
+ cell_renderer,
+ "markup", RESULT_DATA,
+ NULL);
gtk_tree_view_column_add_attribute (column2, cell_renderer, "sensitive", IS_SENSITIVE);
- gtk_tree_view_append_column (GTK_TREE_VIEW (results_list), column2);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (*results_list), column2);
gtk_tree_view_column_set_max_width (column2, wid1);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sc_win),
- GTK_POLICY_NEVER,
- GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (*list_view),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
- gtk_container_add (GTK_CONTAINER (sc_win), results_list);
+ gtk_container_add (GTK_CONTAINER (*list_view), *results_list);
g_object_unref (G_OBJECT (store));
-
- return sc_win;
}
-static gboolean
-action_search_search_dialog (void)
+static void
+search_dialog_free (SearchDialog *private)
{
- GtkWidget *main_vbox, *main_hbox;
- GtkWidget *preferences_image;
- GtkWidget *preferences_button;
- GtkWidget *list_view;
-
- action_search_dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-
- gtk_window_set_decorated (GTK_WINDOW (action_search_dialog), FALSE);
- gtk_window_set_default_size (GTK_WINDOW (action_search_dialog), (PREF.WIDTH/100)*par_width,
DEFAULT_HEIGHT);
- action_search_update_position ();
- gtk_window_set_opacity (GTK_WINDOW (action_search_dialog), PREF.OPACITY);
-
- main_vbox = gtk_vbox_new (FALSE, 2);
- gtk_container_add (GTK_CONTAINER (action_search_dialog), main_vbox);
- gtk_widget_show (main_vbox);
-
- main_hbox = gtk_hbox_new (FALSE, 2);
- gtk_box_pack_start (GTK_BOX (main_vbox), main_hbox, FALSE, TRUE, 0);
- gtk_widget_show (main_hbox);
-
- keyword_entry = gtk_entry_new ();
- gtk_entry_set_has_frame (GTK_ENTRY (keyword_entry), FALSE);
- gtk_entry_set_icon_from_stock (GTK_ENTRY (keyword_entry), GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_FIND);
- gtk_widget_show (keyword_entry);
- gtk_box_pack_start (GTK_BOX (main_hbox), keyword_entry, TRUE, TRUE, 0);
-
- preferences_image = gtk_image_new_from_stock (GTK_STOCK_PROPERTIES, GTK_ICON_SIZE_MENU);
- preferences_button = gtk_button_new ();
- gtk_button_set_image (GTK_BUTTON (preferences_button), preferences_image);
- gtk_widget_show (preferences_image);
- gtk_widget_show (preferences_button);
- gtk_box_pack_end (GTK_BOX (main_hbox), preferences_button, FALSE, TRUE, 0);
-
- list_view = action_search_setup_results_list ();
- gtk_box_pack_start (GTK_BOX (main_vbox), list_view, TRUE, TRUE, 0);
-
-
- gtk_widget_set_events (action_search_dialog, GDK_KEY_RELEASE_MASK);
- gtk_widget_set_events (action_search_dialog, GDK_KEY_PRESS_MASK);
- gtk_widget_set_events (action_search_dialog, GDK_BUTTON_PRESS_MASK);
- gtk_widget_set_events (preferences_button, GDK_BUTTON_PRESS_MASK);
-
- g_signal_connect (results_list, "row-activated", (GCallback) row_activated, NULL);
- g_signal_connect (keyword_entry, "key-release-event", G_CALLBACK (key_released), list_view);
- g_signal_connect (results_list, "key_press_event", G_CALLBACK (result_selected), NULL);
- g_signal_connect (preferences_button, "clicked", G_CALLBACK (context_menu_invoked), NULL);
- g_signal_connect (action_search_dialog, "focus-out-event", G_CALLBACK (on_focus_out), preferences_button);
-
- gtk_widget_show (action_search_dialog);
-
- return TRUE;
+ g_slice_free (SearchDialog, private);
}
diff --git a/app/dialogs/action-search-dialog.h b/app/dialogs/action-search-dialog.h
index 162efe4..6bc2c40 100644
--- a/app/dialogs/action-search-dialog.h
+++ b/app/dialogs/action-search-dialog.h
@@ -18,7 +18,6 @@
#ifndef __ACTION_SEARCH_DIALOG_H__
#define __ACTION_SEARCH_DIALOG_H__
-
-GtkWidget * action_search_dialog_create (void);
+GtkWidget * action_search_dialog_create (Gimp *gimp);
#endif /* __ACTION_SEARCH_DIALOG_H__ */
diff --git a/app/dialogs/dialogs-constructors.c b/app/dialogs/dialogs-constructors.c
index 09e2448..cf02ef8 100644
--- a/app/dialogs/dialogs-constructors.c
+++ b/app/dialogs/dialogs-constructors.c
@@ -201,7 +201,7 @@ dialogs_action_search_get (GimpDialogFactory *factory,
GimpUIManager *ui_manager,
gint view_size)
{
- return action_search_dialog_create ();
+ return action_search_dialog_create (context->gimp);
}
GtkWidget *
diff --git a/app/dialogs/preferences-dialog.c b/app/dialogs/preferences-dialog.c
index 7a9c118..b2cc034 100644
--- a/app/dialogs/preferences-dialog.c
+++ b/app/dialogs/preferences-dialog.c
@@ -53,6 +53,7 @@
#include "widgets/gimptooleditor.h"
#include "widgets/gimpwidgets-constructors.h"
#include "widgets/gimpwidgets-utils.h"
+#include "widgets/gimpaction-history.h"
#include "menus/menus.h"
@@ -113,6 +114,8 @@ static void prefs_devices_save_callback (GtkWidget *widget,
Gimp *gimp);
static void prefs_devices_clear_callback (GtkWidget *widget,
Gimp *gimp);
+static void prefs_search_empty_callback (GtkWidget *widget,
+ gpointer user_data);
static void prefs_tool_options_save_callback (GtkWidget *widget,
Gimp *gimp);
static void prefs_tool_options_clear_callback (GtkWidget *widget,
@@ -646,6 +649,13 @@ prefs_devices_clear_callback (GtkWidget *widget,
}
static void
+prefs_search_empty_callback (GtkWidget *widget,
+ gpointer user_data)
+{
+ gimp_action_history_empty ();
+}
+
+static void
prefs_tool_options_save_callback (GtkWidget *widget,
Gimp *gimp)
{
@@ -1670,10 +1680,30 @@ prefs_dialog_new (Gimp *gimp,
_("H_elp browser to use:"),
GTK_TABLE (table), 0, size_group);
+ /* Action Search */
+ vbox2 = prefs_frame_new (_("Action Search"), GTK_CONTAINER (vbox), FALSE);
+ table = prefs_table_new (1, GTK_CONTAINER (vbox2));
+
+ prefs_check_button_add (object, "search-show-unavailable-actions",
+ _("Show _unavailable actions"),
+ GTK_BOX (vbox2));
+ prefs_spin_button_add (object, "action-history-size", 1.0, 10.0, 0,
+ _("Maximum History Size:"),
+ GTK_TABLE (table), 0, size_group);
+ prefs_spin_button_add (object, "search-dialog-opacity", 1.0, 10.0, 0,
+ _("Search Dialog Opacity:"),
+ GTK_TABLE (table), 3, size_group);
+
+ button = prefs_button_add (GTK_STOCK_CLEAR,
+ _("Clear Action History"),
+ GTK_BOX (vbox2));
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (prefs_search_empty_callback),
+ NULL);
+
g_object_unref (size_group);
size_group = NULL;
-
/******************/
/* Tool Options */
/******************/
diff --git a/app/gui/gui.c b/app/gui/gui.c
index dbd23a9..8cc8499 100644
--- a/app/gui/gui.c
+++ b/app/gui/gui.c
@@ -61,6 +61,7 @@
#include "widgets/gimpuimanager.h"
#include "widgets/gimpwidgets-utils.h"
#include "widgets/gimplanguagestore-parser.h"
+#include "widgets/gimpaction-history.h"
#include "actions/actions.h"
#include "actions/windows-commands.h"
@@ -476,6 +477,7 @@ gui_restore_after_callback (Gimp *gimp,
gimp,
gui_config->tearoff_menus);
gimp_ui_manager_update (image_ui_manager, gimp);
+ gimp_action_history_init (gui_config);
#ifdef GDK_WINDOWING_QUARTZ
{
@@ -644,6 +646,7 @@ gui_exit_after_callback (Gimp *gimp,
gui_show_tooltips_notify,
gimp);
+ gimp_action_history_exit (GIMP_GUI_CONFIG (gimp->config));
g_object_unref (image_ui_manager);
image_ui_manager = NULL;
diff --git a/app/gui/session.c b/app/gui/session.c
index 878ab1a..954e47c 100644
--- a/app/gui/session.c
+++ b/app/gui/session.c
@@ -61,6 +61,11 @@ enum
HIDE_DOCKS,
SINGLE_WINDOW_MODE,
TABS_POSITION,
+ SEARCH_DIALOG_POS_X,
+ SEARCH_DIALOG_POS_Y,
+ SEARCH_DIALOG_WIDTH,
+ SEARCH_DIALOG_HEIGHT,
+ SEARCH_DIALOG_OPACITY,
LAST_TIP_SHOWN
};
@@ -117,6 +122,16 @@ session_init (Gimp *gimp)
GINT_TO_POINTER (SINGLE_WINDOW_MODE));
g_scanner_scope_add_symbol (scanner, 0, "tabs-position",
GINT_TO_POINTER (TABS_POSITION));
+ g_scanner_scope_add_symbol (scanner, 0, "search-dialog-position-x",
+ GINT_TO_POINTER (SEARCH_DIALOG_POS_X));
+ g_scanner_scope_add_symbol (scanner, 0, "search-dialog-position-y",
+ GINT_TO_POINTER (SEARCH_DIALOG_POS_Y));
+ g_scanner_scope_add_symbol (scanner, 0, "search-dialog-width",
+ GINT_TO_POINTER (SEARCH_DIALOG_WIDTH));
+ g_scanner_scope_add_symbol (scanner, 0, "search-dialog-height",
+ GINT_TO_POINTER (SEARCH_DIALOG_HEIGHT));
+ g_scanner_scope_add_symbol (scanner, 0, "search-dialog-opacity",
+ GINT_TO_POINTER (SEARCH_DIALOG_OPACITY));
g_scanner_scope_add_symbol (scanner, 0, "last-tip-shown",
GINT_TO_POINTER (LAST_TIP_SHOWN));
@@ -268,6 +283,71 @@ session_init (Gimp *gimp)
"tabs-position", tabs_position,
NULL);
}
+ else if (scanner->value.v_symbol == GINT_TO_POINTER (SEARCH_DIALOG_POS_X))
+ {
+ gint pos;
+
+ token = G_TOKEN_INT;
+
+ if (! gimp_scanner_parse_int (scanner, &pos))
+ break;
+
+ g_object_set (gimp->config,
+ "search-dialog-position-x", pos,
+ NULL);
+ }
+ else if (scanner->value.v_symbol == GINT_TO_POINTER (SEARCH_DIALOG_POS_Y))
+ {
+ gint pos;
+
+ token = G_TOKEN_INT;
+
+ if (! gimp_scanner_parse_int (scanner, &pos))
+ break;
+
+ g_object_set (gimp->config,
+ "search-dialog-position-y", pos,
+ NULL);
+ }
+ else if (scanner->value.v_symbol == GINT_TO_POINTER (SEARCH_DIALOG_WIDTH))
+ {
+ gint pos;
+
+ token = G_TOKEN_INT;
+
+ if (! gimp_scanner_parse_int (scanner, &pos))
+ break;
+
+ g_object_set (gimp->config,
+ "search-dialog-width", pos,
+ NULL);
+ }
+ else if (scanner->value.v_symbol == GINT_TO_POINTER (SEARCH_DIALOG_HEIGHT))
+ {
+ gint pos;
+
+ token = G_TOKEN_INT;
+
+ if (! gimp_scanner_parse_int (scanner, &pos))
+ break;
+
+ g_object_set (gimp->config,
+ "search-dialog-height", pos,
+ NULL);
+ }
+ else if (scanner->value.v_symbol == GINT_TO_POINTER (SEARCH_DIALOG_OPACITY))
+ {
+ gint pos;
+
+ token = G_TOKEN_INT;
+
+ if (! gimp_scanner_parse_int (scanner, &pos))
+ break;
+
+ g_object_set (gimp->config,
+ "search-dialog-opacity", pos,
+ NULL);
+ }
else if (scanner->value.v_symbol == GINT_TO_POINTER (LAST_TIP_SHOWN))
{
gint last_tip_shown;
@@ -395,6 +475,31 @@ session_save (Gimp *gimp,
GIMP_GUI_CONFIG (gimp->config)->tabs_position);
gimp_config_writer_close (writer);
+ gimp_config_writer_open (writer, "search-dialog-position-x");
+ gimp_config_writer_printf (writer, "%d",
+ GIMP_GUI_CONFIG (gimp->config)->search_dialog_x);
+ gimp_config_writer_close (writer);
+
+ gimp_config_writer_open (writer, "search-dialog-position-y");
+ gimp_config_writer_printf (writer, "%d",
+ GIMP_GUI_CONFIG (gimp->config)->search_dialog_y);
+ gimp_config_writer_close (writer);
+
+ gimp_config_writer_open (writer, "search-dialog-width");
+ gimp_config_writer_printf (writer, "%d",
+ GIMP_GUI_CONFIG (gimp->config)->search_dialog_width);
+ gimp_config_writer_close (writer);
+
+ gimp_config_writer_open (writer, "search-dialog-height");
+ gimp_config_writer_printf (writer, "%d",
+ GIMP_GUI_CONFIG (gimp->config)->search_dialog_height);
+ gimp_config_writer_close (writer);
+
+ gimp_config_writer_open (writer, "search-dialog-opacity");
+ gimp_config_writer_printf (writer, "%d",
+ GIMP_GUI_CONFIG (gimp->config)->search_dialog_opacity);
+ gimp_config_writer_close (writer);
+
gimp_config_writer_open (writer, "last-tip-shown");
gimp_config_writer_printf (writer, "%d",
GIMP_GUI_CONFIG (gimp->config)->last_tip_shown);
diff --git a/app/widgets/Makefile.am b/app/widgets/Makefile.am
index 80bb889..3948910 100644
--- a/app/widgets/Makefile.am
+++ b/app/widgets/Makefile.am
@@ -223,6 +223,8 @@ libappwidgets_a_sources = \
gimplanguagestore.h \
gimplanguagestore-parser.c \
gimplanguagestore-parser.h \
+ gimpaction-history.c \
+ gimpaction-history.h \
gimplayertreeview.c \
gimplayertreeview.h \
gimpmenudock.c \
diff --git a/app/widgets/gimpaction-history.c b/app/widgets/gimpaction-history.c
new file mode 100644
index 0000000..ce9d73a
--- /dev/null
+++ b/app/widgets/gimpaction-history.c
@@ -0,0 +1,296 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 2013 Jehan <jehan at girinstud.io>
+ *
+ * gimpaction-history.c
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <ctype.h>
+
+#include <gtk/gtk.h>
+
+#include "libgimpbase/gimpbase.h"
+
+#include "widgets-types.h"
+
+#include "config/gimpguiconfig.h"
+
+#include "gimpuimanager.h"
+#include "gimpaction.h"
+#include "gimpaction-history.h"
+
+#define GIMP_ACTION_HISTORY_FILENAME "action_history"
+
+typedef struct {
+ GtkAction *action;
+ gchar *name;
+ gint count;
+} GimpActionHistoryItem;
+
+static GList *history = NULL;
+
+static void gimp_action_history_item_free (GimpActionHistoryItem *item);
+
+static gint gimp_action_history_init_compare_func (GimpActionHistoryItem *a,
+ GimpActionHistoryItem *b);
+static gint gimp_action_history_compare_func (GimpActionHistoryItem *a,
+ GimpActionHistoryItem *b);
+
+static void gimp_action_insert (const gchar *action_name,
+ gint count);
+
+/* public functions */
+
+void
+gimp_action_history_init (GimpGuiConfig *config)
+{
+ gchar *history_file_path;
+ gint i;
+ FILE *fp;
+
+ if (history != NULL)
+ {
+ g_warning ("%s: must be run only once.", G_STRFUNC);
+ return;
+ }
+
+ history_file_path = g_build_filename (gimp_directory (),
+ GIMP_ACTION_HISTORY_FILENAME,
+ NULL);
+ fp = fopen (history_file_path, "r");
+ if (fp == NULL)
+ /* Probably a first use case. Not necessarily an error. */
+ return;
+
+ for (i = 0; i < config->action_history_size; i++)
+ {
+ /* Let's assume an action name will never be more than 256 character. */
+ gchar action_name[256];
+ int count;
+
+ if (fscanf (fp, "%s %d", action_name, &count) == EOF)
+ break;
+
+ gimp_action_insert (action_name, count);
+ }
+
+ g_free (history_file_path);
+
+ fclose (fp);
+}
+
+void
+gimp_action_history_exit (GimpGuiConfig *config)
+{
+ GList *actions = history;
+ gchar *history_file_path;
+ FILE *fp;
+ gint i = config->action_history_size;
+
+ history_file_path = g_build_filename (gimp_directory (),
+ GIMP_ACTION_HISTORY_FILENAME,
+ NULL);
+ fp = fopen (history_file_path, "w");
+
+ for (; actions && i; actions = g_list_next (actions), i--)
+ {
+ GimpActionHistoryItem *action = actions->data;
+
+ fprintf (fp, "%s %d \n", action->name, action->count);
+ }
+
+ gimp_action_history_empty ();
+ fclose (fp);
+ g_free (history_file_path);
+}
+
+/* Callback run on the `activate` signal of an action.
+ It allows us to log all used action. */
+void
+gimp_action_history_activate_callback (GtkAction *action,
+ gpointer user_data)
+{
+ GList *actions;
+ GimpActionHistoryItem *history_item;
+ const gchar *action_name;
+
+ action_name = gtk_action_get_name (action);
+
+ /* Some specific actions are of no log interest. */
+ if (g_str_has_suffix (action_name, "-menu") ||
+ g_str_has_suffix (action_name, "-popup") ||
+ g_str_has_prefix (action_name, "context-"))
+ return;
+
+ for (actions = history; actions; actions = g_list_next (actions))
+ {
+ history_item = actions->data;
+
+ if (g_strcmp0 (action_name, history_item->name) == 0)
+ {
+ history_item->count++;
+ /* Remove then reinsert to reorder. */
+ history = g_list_remove (history, history_item);
+ history = g_list_insert_sorted (history, history_item,
+ (GCompareFunc) gimp_action_history_compare_func);
+ return;
+ }
+ }
+
+ /* If we are here, this action is not logged yet. */
+ history_item = g_malloc0 (sizeof (GimpActionHistoryItem));
+
+ history_item->action = g_object_ref (action);
+ history_item->name = g_strdup (action_name);
+ history_item->count = 1;
+ history = g_list_insert_sorted (history,
+ history_item,
+ (GCompareFunc) gimp_action_history_compare_func);
+}
+
+void
+gimp_action_history_empty (void)
+{
+ g_list_free_full (history, (GDestroyNotify) gimp_action_history_item_free);
+ history = NULL;
+}
+
+/* Search all history actions which match "keyword"
+ with function match_func(action, keyword).
+
+ @return a list of GtkAction*, to free with:
+ g_list_free_full (result, (GDestroyNotify) g_object_unref);
+ */
+GList*
+gimp_action_history_search (const gchar *keyword,
+ GimpActionMatchFunc match_func,
+ GimpGuiConfig *config)
+{
+ GList *actions;
+ GimpActionHistoryItem *history_item;
+ GtkAction *action;
+ GList *search_result = NULL;
+ gint i = config->action_history_size;
+
+ for (actions = history; actions && i; actions = g_list_next (actions), i--)
+ {
+ history_item = actions->data;
+ action = history_item->action;
+
+ if (! gtk_action_get_sensitive (action) && ! config->search_show_unavailable)
+ continue;
+
+ if (match_func (action, keyword))
+ search_result = g_list_prepend (search_result, g_object_ref (action));
+ }
+
+ return g_list_reverse (search_result);
+}
+
+/* private functions */
+
+static void
+gimp_action_history_item_free (GimpActionHistoryItem *item)
+{
+ g_object_unref (item->action);
+ g_free (item->name);
+ g_free (item);
+}
+
+/* Compare function used at list initialization.
+ We use a slightly different compare function as for runtime insert,
+ because we want to keep history file order for equal values. */
+static gint
+gimp_action_history_init_compare_func (GimpActionHistoryItem *a,
+ GimpActionHistoryItem *b)
+{
+ return (a->count <= b->count);
+}
+
+/* Compare function used when updating the list.
+ There is no equality case. If they have the same count,
+ I ensure that the first action (last inserted) will be before. */
+static gint
+gimp_action_history_compare_func (GimpActionHistoryItem *a,
+ GimpActionHistoryItem *b)
+{
+ return (a->count < b->count);
+}
+
+static void
+gimp_action_insert (const gchar *action_name,
+ gint count)
+{
+ GList *action_groups;
+ GimpUIManager *manager;
+
+ /* We do not insert some categories of actions. */
+ if (g_str_has_suffix (action_name, "-menu") ||
+ g_str_has_suffix (action_name, "-popup") ||
+ g_str_has_prefix (action_name, "context-"))
+ return;
+
+ manager = gimp_ui_managers_from_name ("<Image>")->data;
+
+ for (action_groups = gtk_ui_manager_get_action_groups (GTK_UI_MANAGER (manager));
+ action_groups;
+ action_groups = g_list_next (action_groups))
+ {
+ GimpActionGroup *group = action_groups->data;
+ GList *actions;
+ GList *list2;
+ gboolean found = FALSE;
+
+ actions = gtk_action_group_list_actions (GTK_ACTION_GROUP (group));
+ actions = g_list_sort (actions, (GCompareFunc) gimp_action_name_compare);
+
+ for (list2 = actions; list2; list2 = g_list_next (list2))
+ {
+ GtkAction *action = list2->data;
+ gint unavailable_action = -1;
+
+ unavailable_action = strcmp (action_name, gtk_action_get_name (action));
+
+ if (unavailable_action == 0)
+ {
+ /* We found our action. */
+ GimpActionHistoryItem *new_action = g_malloc0 (sizeof (GimpActionHistoryItem));
+
+ new_action->action = g_object_ref (action);
+ new_action->name = g_strdup (action_name);
+ new_action->count = count;
+ history = g_list_insert_sorted (history,
+ new_action,
+ (GCompareFunc) gimp_action_history_init_compare_func);
+ found = TRUE;
+ break;
+ }
+ else if (unavailable_action < 0)
+ {
+ /* Since the actions list is sorted, it means we passed
+ all possible actions already and it is not in this group. */
+ break;
+ }
+
+ }
+ g_list_free (actions);
+
+ if (found)
+ break;
+ }
+}
diff --git a/app/widgets/gimpaction-history.h b/app/widgets/gimpaction-history.h
new file mode 100644
index 0000000..bba0aeb
--- /dev/null
+++ b/app/widgets/gimpaction-history.h
@@ -0,0 +1,38 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 2013 Jehan <jehan at girinstud.io>
+ *
+ * gimpaction-history.h
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_ACTION_HISTORY_H__
+#define __GIMP_ACTION_HISTORY_H__
+
+typedef gboolean (* GimpActionMatchFunc) (GtkAction *action,
+ const gchar* keyword);
+
+void gimp_action_history_init (GimpGuiConfig *config);
+void gimp_action_history_exit (GimpGuiConfig *config);
+
+void gimp_action_history_activate_callback (GtkAction *action,
+ gpointer user_data);
+
+void gimp_action_history_empty (void);
+
+GList * gimp_action_history_search (const gchar *keyword,
+ GimpActionMatchFunc match_func,
+ GimpGuiConfig *config);
+
+#endif /* __GIMP_ACTION_HISTORY_H__ */
diff --git a/app/widgets/gimpaction.c b/app/widgets/gimpaction.c
index ff3db4c..ffc68fb 100644
--- a/app/widgets/gimpaction.c
+++ b/app/widgets/gimpaction.c
@@ -37,6 +37,7 @@
#include "core/gimpviewable.h"
#include "gimpaction.h"
+#include "gimpaction-history.h"
#include "gimpview.h"
#include "gimpviewrenderer.h"
@@ -52,6 +53,7 @@ enum
};
+static void gimp_action_constructed (GObject *object);
static void gimp_action_finalize (GObject *object);
static void gimp_action_set_property (GObject *object,
guint prop_id,
@@ -85,6 +87,7 @@ gimp_action_class_init (GimpActionClass *klass)
GtkActionClass *action_class = GTK_ACTION_CLASS (klass);
GimpRGB black;
+ object_class->constructed = gimp_action_constructed;
object_class->finalize = gimp_action_finalize;
object_class->set_property = gimp_action_set_property;
object_class->get_property = gimp_action_get_property;
@@ -139,6 +142,16 @@ gimp_action_init (GimpAction *action)
}
static void
+gimp_action_constructed (GObject *object)
+{
+ GimpAction *action = GIMP_ACTION (object);
+
+ g_signal_connect (action, "activate",
+ (GCallback) gimp_action_history_activate_callback,
+ NULL);
+}
+
+static void
gimp_action_finalize (GObject *object)
{
GimpAction *action = GIMP_ACTION (object);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]