2
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
4
* This is a plug-in for the GIMP.
6
* Copyright (C) 1999 Andy Thomas alt@picnic.demon.co.uk
8
* Note some portions of the UI comes from the dbbrowser plugin.
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or
12
* (at your option) any later version.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31
#include <libgimp/gimp.h>
32
#include <libgimp/gimpui.h>
34
#include "libgimp/stdplugins-intl.h"
37
#define PLUG_IN_PROC "plug-in-plug-in-details"
38
#define PLUG_IN_BINARY "plugin-browser"
39
#define DBL_LIST_WIDTH 250
40
#define DBL_WIDTH (DBL_LIST_WIDTH + 400)
41
#define DBL_HEIGHT 250
48
LIST_COLUMN_DATE_STRING,
50
LIST_COLUMN_IMAGE_TYPES,
57
TREE_COLUMN_PATH_NAME,
59
TREE_COLUMN_DATE_STRING,
60
TREE_COLUMN_IMAGE_TYPES,
72
GtkTreeView *list_view;
73
GtkTreeView *tree_view;
87
/* Declare some local functions.
89
static void query (void);
90
static void run (const gchar *name,
92
const GimpParam *param,
94
GimpParam **return_vals);
97
static GtkWidget * browser_dialog_new (void);
98
static void browser_dialog_response (GtkWidget *widget,
100
PluginBrowser *browser);
101
static void browser_list_selection_changed (GtkTreeSelection *selection,
102
PluginBrowser *browser);
103
static void browser_tree_selection_changed (GtkTreeSelection *selection,
104
PluginBrowser *browser);
105
static void browser_show_plugin (PluginBrowser *browser,
108
static gboolean find_existing_mpath (GtkTreeModel *model,
110
GtkTreeIter *return_iter);
113
const GimpPlugInInfo PLUG_IN_INFO =
115
NULL, /* init_proc */
116
NULL, /* quit_proc */
117
query, /* query_proc */
128
static const GimpParamDef args[] =
130
{ GIMP_PDB_INT32, "run-mode", "Interactive, [non-interactive]" }
133
gimp_install_procedure (PLUG_IN_PROC,
134
N_("Display information about plug-ins"),
135
"Allows to browse the plug-in menus system. You can "
136
"search for plug-in names, sort by name or menu "
137
"location and you can view a tree representation "
138
"of the plug-in menus. Can also be of help to find "
139
"where new plug-ins have installed themselves in "
144
N_("_Plug-In Browser"),
147
G_N_ELEMENTS (args), 0,
150
gimp_plugin_menu_register (PLUG_IN_PROC, "<Toolbox>/Xtns/Extensions");
151
gimp_plugin_icon_register (PLUG_IN_PROC, GIMP_ICON_TYPE_STOCK_ID,
152
(const guint8 *) GIMP_STOCK_PLUGIN);
156
run (const gchar *name,
158
const GimpParam *param,
160
GimpParam **return_vals)
162
static GimpParam values[2];
163
GimpRunMode run_mode;
165
run_mode = param[0].data.d_int32;
168
*return_vals = values;
170
values[0].type = GIMP_PDB_STATUS;
171
values[0].data.d_status = GIMP_PDB_CALLING_ERROR;
175
if (strcmp (name, PLUG_IN_PROC) == 0)
179
values[0].data.d_status = GIMP_PDB_SUCCESS;
181
browser_dialog_new ();
187
find_existing_mpath_helper (GtkTreeModel *model,
191
GtkTreeIter *return_iter)
198
gtk_tree_model_get (model, iter,
199
TREE_COLUMN_MPATH, &picked_mpath,
202
if (! strcmp (mpath, picked_mpath))
204
*return_iter = *iter;
205
g_free (picked_mpath);
209
if (gtk_tree_model_iter_children (model, &child, iter))
211
gtk_tree_path_down (path);
213
if (find_existing_mpath_helper (model, &child, path,
216
g_free (picked_mpath);
220
gtk_tree_path_up (path);
223
gtk_tree_path_next (path);
224
g_free (picked_mpath);
226
while (gtk_tree_model_iter_next (model, iter));
232
find_existing_mpath (GtkTreeModel *model,
234
GtkTreeIter *return_iter)
236
GtkTreePath *path = gtk_tree_path_new_first ();
240
if (! gtk_tree_model_get_iter (model, &parent, path))
242
gtk_tree_path_free (path);
246
found = find_existing_mpath_helper (model, &parent, path, mpath, return_iter);
248
gtk_tree_path_free (path);
254
get_parent (PluginBrowser *browser,
258
GtkTreeIter last_parent;
261
const gchar *leaf_ptr;
262
GtkTreeStore *tree_store;
267
tree_store = GTK_TREE_STORE (gtk_tree_view_get_model (browser->tree_view));
269
/* Lookup for existing mpath */
270
if (find_existing_mpath (GTK_TREE_MODEL (tree_store), mpath, parent))
273
tmp_ptr = g_strdup (mpath);
275
/* Strip off trailing ellipsis */
276
str_ptr = strstr (mpath, "...");
277
if (str_ptr && str_ptr == (mpath + strlen (mpath) - 3))
280
str_ptr = strrchr (tmp_ptr, '/');
285
gtk_tree_store_append (tree_store, parent, NULL);
286
gtk_tree_store_set (tree_store, parent,
287
TREE_COLUMN_MPATH, mpath,
288
TREE_COLUMN_PATH_NAME, mpath,
293
leaf_ptr = g_strdup (str_ptr + 1);
297
get_parent (browser, tmp_ptr, &last_parent);
298
gtk_tree_store_append (tree_store, parent, &last_parent);
299
gtk_tree_store_set (tree_store, parent,
300
TREE_COLUMN_MPATH, mpath,
301
TREE_COLUMN_PATH_NAME, leaf_ptr,
307
insert_into_tree_view (PluginBrowser *browser,
310
const gchar *xtimestr,
311
const gchar *menu_str,
312
const gchar *types_str,
319
GtkTreeIter parent, iter;
320
GtkTreeStore *tree_store;
323
/* Last one is the leaf part */
325
tmp_ptr = g_strdup (menu_str);
327
str_ptr = strrchr (tmp_ptr, '/');
330
return; /* No node */
332
leaf_ptr = g_strdup (str_ptr + 1);
336
/* printf("inserting %s...\n",menu_str); */
338
get_parent (browser, tmp_ptr, &parent);
340
/* Last was a leaf */
341
/* printf("found leaf %s parent = %p\n",leaf_ptr,parent); */
342
labels[0] = g_strdup (name);
343
labels[1] = g_strdup (xtimestr);
344
labels[2] = g_strdup (types_str);
346
tree_store = GTK_TREE_STORE (gtk_tree_view_get_model (browser->tree_view));
347
gtk_tree_store_append (tree_store, &iter, &parent);
348
gtk_tree_store_set (tree_store, &iter,
349
TREE_COLUMN_MPATH, menu_str,
350
TREE_COLUMN_PATH_NAME, name,
351
TREE_COLUMN_IMAGE_TYPES, types_str,
352
TREE_COLUMN_DATE, xtime,
353
TREE_COLUMN_DATE_STRING, xtimestr,
354
TREE_COLUMN_PINFO, pinfo,
359
browser_search (GimpBrowser *gimp_browser,
360
const gchar *search_text,
362
PluginBrowser *browser)
364
GimpParam *return_vals;
368
GtkListStore *list_store;
369
GtkTreeStore *tree_store;
371
gimp_browser_show_message (GIMP_BROWSER (browser->browser),
372
_("Searching by name"));
374
return_vals = gimp_run_procedure ("gimp-plugins-query",
376
GIMP_PDB_STRING, search_text,
379
if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
380
num_plugins = return_vals[1].data.d_int32;
384
if (! search_text || strlen (search_text) == 0)
386
str = g_strdup_printf (ngettext ("%d plug-in", "%d plug-ins",
395
str = g_strdup (_("No matches for your query"));
398
str = g_strdup_printf (ngettext ("%d plug-in matches your query",
399
"%d plug-ins match your query",
400
num_plugins), num_plugins);
405
gtk_label_set_text (GTK_LABEL (gimp_browser->count_label), str);
408
list_store = GTK_LIST_STORE (gtk_tree_view_get_model (browser->list_view));
409
gtk_list_store_clear (list_store);
411
tree_store = GTK_TREE_STORE (gtk_tree_view_get_model (browser->tree_view));
412
gtk_tree_store_clear (tree_store);
416
GtkTreeSelection *sel;
422
gchar **realname_strs;
426
menu_strs = return_vals[2].data.d_stringarray;
427
accel_strs = return_vals[4].data.d_stringarray;
428
prog_strs = return_vals[6].data.d_stringarray;
429
types_strs = return_vals[8].data.d_stringarray;
430
time_ints = return_vals[10].data.d_int32array;
431
realname_strs = return_vals[12].data.d_stringarray;
433
for (i = 0; i < num_plugins; i++)
442
/* Strip off trailing ellipsis */
443
name = strstr (menu_strs[i], "...");
444
if (name && name == (menu_strs[i] + strlen (menu_strs[i]) - 3))
447
name = strrchr (menu_strs[i], '/');
462
const gchar *format = "%c"; /* gcc workaround to avoid warning */
466
ret = strftime (xtimestr, sizeof (xtimestr), format, x);
469
if ((utf8 = g_locale_to_utf8 (xtimestr, -1, NULL, NULL, NULL)))
471
strncpy (xtimestr, utf8, sizeof (xtimestr));
472
xtimestr[sizeof (xtimestr) - 1] = 0;
478
strcpy (xtimestr, "");
481
pinfo = g_new0 (PInfo, 1);
483
pinfo->menu = g_strdup (menu_strs[i]);
484
pinfo->accel = g_strdup (accel_strs[i]);
485
pinfo->prog = g_strdup (prog_strs[i]);
486
pinfo->types = g_strdup (types_strs[i]);
487
pinfo->instime = time_ints[i];
488
pinfo->realname = g_strdup (realname_strs[i]);
490
gtk_list_store_append (list_store, &iter);
491
gtk_list_store_set (list_store, &iter,
492
LIST_COLUMN_NAME, name,
493
LIST_COLUMN_DATE, (gint64) tx,
494
LIST_COLUMN_DATE_STRING, xtimestr,
495
LIST_COLUMN_PATH, menu_strs[i],
496
LIST_COLUMN_IMAGE_TYPES, types_strs[i],
497
LIST_COLUMN_PINFO, pinfo,
500
/* Now do the tree view.... */
501
insert_into_tree_view (browser,
510
gtk_tree_view_columns_autosize (GTK_TREE_VIEW (browser->list_view));
511
gtk_tree_view_columns_autosize (GTK_TREE_VIEW (browser->tree_view));
513
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store),
516
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (tree_store),
517
TREE_COLUMN_PATH_NAME,
520
sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->list_view));
522
gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store),
524
gtk_tree_selection_select_iter (sel, &iter);
528
gimp_browser_show_message (GIMP_BROWSER (browser->browser),
532
gimp_destroy_params (return_vals, nreturn_vals);
536
browser_dialog_new (void)
538
PluginBrowser *browser;
539
GtkWidget *label, *notebook;
540
GtkWidget *scrolled_window;
541
GtkListStore *list_store;
542
GtkTreeStore *tree_store;
543
GtkWidget *list_view;
544
GtkWidget *tree_view;
545
GtkTreeViewColumn *column;
546
GtkCellRenderer *renderer;
547
GtkTreeSelection *selection;
550
gimp_ui_init (PLUG_IN_BINARY, FALSE);
552
browser = g_new0 (PluginBrowser, 1);
554
browser->dialog = gimp_dialog_new (_("Plug-In Browser"), PLUG_IN_BINARY,
556
gimp_standard_help_func, PLUG_IN_PROC,
558
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
562
g_signal_connect (browser->dialog, "response",
563
G_CALLBACK (browser_dialog_response),
566
browser->browser = gimp_browser_new ();
567
gtk_container_set_border_width (GTK_CONTAINER (browser->browser), 12);
568
gtk_container_add (GTK_CONTAINER (GTK_DIALOG (browser->dialog)->vbox),
570
gtk_widget_show (browser->browser);
572
g_signal_connect (browser->browser, "search",
573
G_CALLBACK (browser_search),
576
/* left = notebook */
578
notebook = gtk_notebook_new ();
579
gtk_box_pack_start (GTK_BOX (GIMP_BROWSER (browser->browser)->left_vbox),
580
notebook, TRUE, TRUE, 0);
582
/* list : list in a scrolled_win */
583
list_store = gtk_list_store_new (N_LIST_COLUMNS,
591
list_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (list_store));
592
g_object_unref (list_store);
594
browser->list_view = GTK_TREE_VIEW (list_view);
596
renderer = gtk_cell_renderer_text_new ();
597
column = gtk_tree_view_column_new_with_attributes (_("Name"),
599
"text", LIST_COLUMN_NAME,
601
gtk_tree_view_column_set_sort_column_id (column, LIST_COLUMN_NAME);
602
gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);
604
renderer = gtk_cell_renderer_text_new ();
605
column = gtk_tree_view_column_new_with_attributes (_("Menu Path"),
607
"text", LIST_COLUMN_PATH,
609
gtk_tree_view_column_set_sort_column_id (column, LIST_COLUMN_PATH);
610
gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);
612
renderer = gtk_cell_renderer_text_new ();
613
column = gtk_tree_view_column_new_with_attributes (_("Image Types"),
616
LIST_COLUMN_IMAGE_TYPES,
618
gtk_tree_view_column_set_sort_column_id (column, LIST_COLUMN_IMAGE_TYPES);
619
gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);
621
renderer = gtk_cell_renderer_text_new ();
623
column = gtk_tree_view_column_new_with_attributes (_("Installation Date"),
626
LIST_COLUMN_DATE_STRING,
628
gtk_tree_view_column_set_sort_column_id (column, LIST_COLUMN_DATE);
629
gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);
631
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
632
gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 2);
633
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
635
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
636
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
638
gtk_widget_set_size_request (list_view, DBL_LIST_WIDTH, DBL_HEIGHT);
640
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
641
gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
643
g_signal_connect (selection, "changed",
644
G_CALLBACK (browser_list_selection_changed),
647
label = gtk_label_new (_("List View"));
648
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled_window, label);
649
gtk_container_add (GTK_CONTAINER (scrolled_window), list_view);
650
gtk_widget_show (list_view);
651
gtk_widget_show (scrolled_window);
653
/* notebook->ctree */
654
tree_store = gtk_tree_store_new (N_LIST_COLUMNS,
662
tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (tree_store));
663
g_object_unref (tree_store);
665
browser->tree_view = GTK_TREE_VIEW (tree_view);
667
renderer = gtk_cell_renderer_text_new ();
668
column = gtk_tree_view_column_new_with_attributes (_("Menu Path"),
671
TREE_COLUMN_PATH_NAME,
673
gtk_tree_view_column_set_sort_column_id (column, TREE_COLUMN_PATH_NAME);
674
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
676
renderer = gtk_cell_renderer_text_new ();
677
column = gtk_tree_view_column_new_with_attributes (_("Image Types"),
680
TREE_COLUMN_IMAGE_TYPES,
682
gtk_tree_view_column_set_sort_column_id (column, TREE_COLUMN_IMAGE_TYPES);
683
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
685
renderer = gtk_cell_renderer_text_new ();
686
column = gtk_tree_view_column_new_with_attributes (_("Installation Date"),
689
TREE_COLUMN_DATE_STRING,
691
gtk_tree_view_column_set_sort_column_id (column, TREE_COLUMN_DATE);
692
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
694
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
695
gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 2);
696
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
698
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
699
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
700
gtk_widget_set_size_request (tree_view, DBL_LIST_WIDTH, DBL_HEIGHT);
702
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
703
gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
705
g_signal_connect (selection, "changed",
706
G_CALLBACK (browser_tree_selection_changed),
709
label = gtk_label_new (_("Tree View"));
710
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled_window, label);
711
gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
713
gtk_widget_show (tree_view);
714
gtk_widget_show (scrolled_window);
715
gtk_widget_show (notebook);
717
gtk_widget_set_size_request (GIMP_BROWSER (browser->browser)->right_vbox->parent->parent,
718
DBL_WIDTH - DBL_LIST_WIDTH, -1);
720
/* now build the list */
721
browser_search (GIMP_BROWSER (browser->browser), "", 0, browser);
723
gtk_widget_show (browser->dialog);
725
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store), &iter))
726
gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view)),
729
return browser->dialog;
733
browser_dialog_response (GtkWidget *widget,
735
PluginBrowser *browser)
737
gtk_widget_destroy (browser->dialog);
742
browser_list_selection_changed (GtkTreeSelection *selection,
743
PluginBrowser *browser)
750
g_return_if_fail (browser != NULL);
752
if (gtk_tree_selection_get_selected (selection, &model, &iter))
754
gtk_tree_model_get (model, &iter,
755
LIST_COLUMN_PINFO, &pinfo,
756
LIST_COLUMN_PATH, &mpath,
760
if (!pinfo || !mpath)
763
model = gtk_tree_view_get_model (browser->tree_view);
765
if (find_existing_mpath (model, mpath, &iter))
767
GtkTreeSelection *tree_selection;
768
GtkTreePath *tree_path;
770
tree_path = gtk_tree_model_get_path (model, &iter);
771
gtk_tree_view_expand_to_path (browser->tree_view, tree_path);
772
tree_selection = gtk_tree_view_get_selection (browser->tree_view);
774
g_signal_handlers_block_by_func (tree_selection,
775
browser_tree_selection_changed,
777
gtk_tree_selection_select_iter (tree_selection, &iter);
778
g_signal_handlers_unblock_by_func (tree_selection,
779
browser_tree_selection_changed,
782
gtk_tree_view_scroll_to_cell (browser->tree_view,
788
g_warning ("Failed to find node in tree");
793
browser_show_plugin (browser, pinfo);
797
browser_tree_selection_changed (GtkTreeSelection *selection,
798
PluginBrowser *browser)
804
gboolean valid, found;
806
g_return_if_fail (browser != NULL);
808
if (gtk_tree_selection_get_selected (selection, &model, &iter))
810
gtk_tree_model_get (model, &iter,
811
TREE_COLUMN_PINFO, &pinfo,
812
TREE_COLUMN_MPATH, &mpath,
816
if (!pinfo || !mpath)
819
/* Get the first iter in the list */
820
model = gtk_tree_view_get_model (browser->list_view);
821
valid = gtk_tree_model_get_iter_first (model, &iter);
826
/* Walk through the list, reading each row */
829
gtk_tree_model_get (model, &iter,
830
LIST_COLUMN_PATH, &picked_mpath,
832
if (picked_mpath && !strcmp (mpath, picked_mpath))
838
g_free (picked_mpath);
839
valid = gtk_tree_model_iter_next (model, &iter);
846
GtkTreeSelection *list_selection;
847
GtkTreePath *tree_path;
849
tree_path = gtk_tree_model_get_path (model, &iter);
850
list_selection = gtk_tree_view_get_selection (browser->list_view);
852
g_signal_handlers_block_by_func (list_selection,
853
browser_list_selection_changed,
855
gtk_tree_selection_select_iter (list_selection, &iter);
856
g_signal_handlers_unblock_by_func (list_selection,
857
browser_list_selection_changed,
860
gtk_tree_view_scroll_to_cell (browser->list_view,
866
g_warning ("Failed to find node in list");
869
browser_show_plugin (browser, pinfo);
873
browser_show_plugin (PluginBrowser *browser,
878
gchar *author = NULL;
879
gchar *copyright = NULL;
881
GimpPDBProcType type = 0;
883
gint n_return_vals = 0;
884
GimpParamDef *params = NULL;
885
GimpParamDef *return_vals = NULL;
887
g_return_if_fail (browser != NULL);
888
g_return_if_fail (pinfo != NULL);
890
gimp_procedural_db_proc_info (pinfo->realname,
902
gimp_browser_set_widget (GIMP_BROWSER (browser->browser),
903
gimp_proc_view_new (pinfo->realname,
922
gimp_destroy_paramdefs (params, n_params);
923
gimp_destroy_paramdefs (return_vals, n_return_vals);