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.
33
#include <libgimp/gimp.h>
34
#include <libgimp/gimpui.h>
36
#include "gimpprocbox.h"
37
#include "gimpprocview.h"
39
#include "libgimp/stdplugins-intl.h"
47
LIST_IMAGE_TYPES_COLUMN,
54
TREE_PATH_NAME_COLUMN,
56
TREE_IMAGE_TYPES_COLUMN,
62
#define DBL_LIST_WIDTH 250
63
#define DBL_WIDTH (DBL_LIST_WIDTH + 400)
64
#define DBL_HEIGHT 250
70
GtkTreeView *list_view;
71
GtkTreeView *tree_view;
73
GtkWidget *count_label;
74
GtkWidget *search_entry;
91
/* Declare some local functions.
93
static void query (void);
94
static void run (const gchar *name,
96
const GimpParam *param,
98
GimpParam **return_vals);
101
static GtkWidget * browser_dialog_new (void);
102
static void browser_dialog_response (GtkWidget *widget,
104
PluginBrowser *browser);
105
static void browser_list_selection_changed (GtkTreeSelection *selection,
106
PluginBrowser *browser);
107
static void browser_tree_selection_changed (GtkTreeSelection *selection,
108
PluginBrowser *browser);
109
static void browser_show_plugin (PluginBrowser *browser,
112
static gboolean find_existing_mpath (GtkTreeModel *model,
114
GtkTreeIter *return_iter);
118
static PluginBrowser *browser = NULL;
120
GimpPlugInInfo PLUG_IN_INFO =
122
NULL, /* init_proc */
123
NULL, /* quit_proc */
124
query, /* query_proc */
135
static GimpParamDef args[] =
137
{ GIMP_PDB_INT32, "run_mode", "Interactive, [non-interactive]" }
140
gimp_install_procedure ("plug_in_plug_in_details",
141
"Displays plug-in details",
142
"Allows to browse the plug-in menus system. You can "
143
"search for plug-in names, sort by name or menu "
144
"location and you can view a tree representation "
145
"of the plug-in menus. Can also be of help to find "
146
"where new plug-ins have installed themselves in "
151
N_("_Plug-In Browser"),
154
G_N_ELEMENTS (args), 0,
157
gimp_plugin_menu_register ("plug_in_plug_in_details",
158
"<Toolbox>/Xtns/Extensions");
159
gimp_plugin_icon_register ("plug_in_plug_in_details",
160
GIMP_ICON_TYPE_STOCK_ID, GIMP_STOCK_PLUGIN);
164
run (const gchar *name,
166
const GimpParam *param,
168
GimpParam **return_vals)
170
static GimpParam values[2];
171
GimpRunMode run_mode;
173
run_mode = param[0].data.d_int32;
176
*return_vals = values;
178
values[0].type = GIMP_PDB_STATUS;
179
values[0].data.d_status = GIMP_PDB_CALLING_ERROR;
183
if (strcmp (name, "plug_in_plug_in_details") == 0)
185
GtkWidget *plugin_dialog;
189
values[0].data.d_status = GIMP_PDB_SUCCESS;
191
plugin_dialog = browser_dialog_new ();
199
pinfo_free (gpointer p)
203
g_free (pinfo->menu);
204
g_free (pinfo->accel);
205
g_free (pinfo->prog);
206
g_free (pinfo->types);
207
g_free (pinfo->realname);
213
find_existing_mpath_helper (GtkTreeModel *model,
217
GtkTreeIter *return_iter)
224
gtk_tree_model_get (model, iter,
225
TREE_MPATH_COLUMN, &picked_mpath,
228
if (! strcmp (mpath, picked_mpath))
230
*return_iter = *iter;
231
g_free (picked_mpath);
235
if (gtk_tree_model_iter_children (model, &child, iter))
237
gtk_tree_path_down (path);
239
if (find_existing_mpath_helper (model, &child, path,
242
g_free (picked_mpath);
246
gtk_tree_path_up (path);
249
gtk_tree_path_next (path);
250
g_free (picked_mpath);
252
while (gtk_tree_model_iter_next (model, iter));
258
find_existing_mpath (GtkTreeModel *model,
260
GtkTreeIter *return_iter)
265
path = gtk_tree_path_new_first ();
267
if (gtk_tree_model_get_iter (model, &parent, path) == FALSE)
269
gtk_tree_path_free (path);
273
return find_existing_mpath_helper (model, &parent, path,
275
gtk_tree_path_free (path);
279
get_parent (PluginBrowser *browser,
283
GtkTreeIter last_parent;
287
GtkTreeStore *tree_store;
292
tree_store = GTK_TREE_STORE (gtk_tree_view_get_model (browser->tree_view));
294
/* Lookup for existing mpath */
295
if (find_existing_mpath (GTK_TREE_MODEL (tree_store), mpath, parent))
299
tmp_ptr = g_strdup (mpath);
301
str_ptr = strrchr (tmp_ptr,'/');
306
gtk_tree_store_append (tree_store, parent, NULL);
307
gtk_tree_store_set (tree_store, parent,
308
TREE_MPATH_COLUMN, mpath,
309
TREE_PATH_NAME_COLUMN, mpath,
314
leaf_ptr = g_strdup(str_ptr+1);
318
get_parent (browser, tmp_ptr, &last_parent);
319
gtk_tree_store_append (tree_store, parent, &last_parent);
320
gtk_tree_store_set (tree_store, parent,
321
TREE_MPATH_COLUMN, mpath,
322
TREE_PATH_NAME_COLUMN, leaf_ptr,
328
insert_into_tree_view (PluginBrowser *browser,
339
GtkTreeIter parent, iter;
340
GtkTreeStore *tree_store;
343
/* Last one is the leaf part */
345
tmp_ptr = g_strdup (menu_str);
347
str_ptr = strrchr (tmp_ptr, '/');
350
return; /* No node */
352
leaf_ptr = g_strdup (str_ptr + 1);
356
/* printf("inserting %s...\n",menu_str); */
358
get_parent (browser, tmp_ptr, &parent);
360
/* Last was a leaf */
361
/* printf("found leaf %s parent = %p\n",leaf_ptr,parent); */
362
labels[0] = g_strdup (name);
363
labels[1] = g_strdup (xtimestr);
364
labels[2] = g_strdup (types_str);
366
tree_store = GTK_TREE_STORE (gtk_tree_view_get_model (browser->tree_view));
367
gtk_tree_store_append (tree_store, &iter, &parent);
368
gtk_tree_store_set (tree_store, &iter,
369
TREE_MPATH_COLUMN, menu_str,
370
TREE_PATH_NAME_COLUMN, name,
371
TREE_IMAGE_TYPES_COLUMN, types_str,
372
TREE_DATE_COLUMN, xtimestr,
373
TREE_PINFO_COLUMN, pinfo,
378
get_plugin_info (PluginBrowser *browser,
379
const gchar *search_text)
381
GimpParam *return_vals;
387
gchar **realname_strs;
389
GtkListStore *list_store;
390
GtkTreeStore *tree_store;
396
gimp_proc_box_show_message (browser->proc_box,
397
_("Searching by name - please wait"));
399
return_vals = gimp_run_procedure ("gimp_plugins_query",
401
GIMP_PDB_STRING, search_text,
404
if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
409
browser->num_plugins = return_vals[1].data.d_int32;
410
menu_strs = return_vals[2].data.d_stringarray;
411
accel_strs = return_vals[4].data.d_stringarray;
412
prog_strs = return_vals[6].data.d_stringarray;
413
types_strs = return_vals[8].data.d_stringarray;
414
time_ints = return_vals[10].data.d_int32array;
415
realname_strs = return_vals[12].data.d_stringarray;
417
if (browser->num_plugins == 1)
418
str = g_strdup (_("1 Plug-In Interface"));
420
str = g_strdup_printf (_("%d Plug-In Interfaces"),
421
browser->num_plugins);
423
gtk_label_set_text (GTK_LABEL (browser->count_label), str);
426
list_store = GTK_LIST_STORE (gtk_tree_view_get_model (browser->list_view));
427
gtk_list_store_clear (list_store);
429
tree_store = GTK_TREE_STORE (gtk_tree_view_get_model (browser->tree_view));
430
gtk_tree_store_clear (tree_store);
432
for (loop = 0; loop < return_vals[1].data.d_int32; loop++)
441
name = strrchr (menu_strs[loop], '/');
446
name = menu_strs[loop];
448
pinfo = g_new0 (PInfo, 1);
450
tx = time_ints[loop];
453
const gchar *format = "%c"; /* gcc workaround to avoid warning */
457
ret = strftime (xtimestr, sizeof (xtimestr), format, x);
460
if ((utf8 = g_locale_to_utf8 (xtimestr, -1, NULL, NULL, NULL)))
462
strncpy (xtimestr, utf8, sizeof (xtimestr));
463
xtimestr[sizeof (xtimestr) - 1] = 0;
468
strcpy (xtimestr,"");
470
pinfo->menu = g_strdup (menu_strs[loop]);
471
pinfo->accel = g_strdup (accel_strs[loop]);
472
pinfo->prog = g_strdup (prog_strs[loop]);
473
pinfo->types = g_strdup (types_strs[loop]);
474
pinfo->instime = time_ints[loop];
475
pinfo->realname = g_strdup (realname_strs[loop]);
477
gtk_list_store_append (list_store, &iter);
478
gtk_list_store_set (list_store, &iter,
479
LIST_NAME_COLUMN, name,
480
LIST_DATE_COLUMN, xtimestr,
481
LIST_PATH_COLUMN, menu_strs[loop],
482
LIST_IMAGE_TYPES_COLUMN, types_strs[loop],
483
LIST_PINFO_COLUMN, pinfo,
486
/* Now do the tree view.... */
487
insert_into_tree_view (browser,
495
gtk_tree_view_columns_autosize (GTK_TREE_VIEW (browser->list_view));
496
gtk_tree_view_columns_autosize (GTK_TREE_VIEW (browser->tree_view));
498
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store),
501
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (tree_store),
502
TREE_PATH_NAME_COLUMN,
505
if (browser->num_plugins)
507
GtkTreeSelection *sel =
508
gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->list_view));
510
gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store),
512
gtk_tree_selection_select_iter (sel, &iter);
516
gimp_proc_box_show_message (browser->proc_box, _("No matches"));
520
gimp_destroy_params (return_vals, nreturn_vals);
524
browser_dialog_new (void)
527
GtkWidget *hbox, *vbox;
528
GtkWidget *label, *notebook, *swindow;
529
GtkListStore *list_store;
530
GtkTreeStore *tree_store;
531
GtkWidget *list_view;
532
GtkWidget *tree_view;
533
GtkTreeViewColumn *column;
534
GtkCellRenderer *renderer;
535
GtkTreeSelection *selection;
538
gimp_ui_init ("plugindetails", FALSE);
540
browser = g_new0 (PluginBrowser, 1);
544
gimp_dialog_new (_("Plug-In Browser"), "plugindetails",
546
gimp_standard_help_func, "plug-in-plug-in-details",
548
_("Search by _Name"), GTK_RESPONSE_OK,
549
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
553
g_signal_connect (browser->dialog, "response",
554
G_CALLBACK (browser_dialog_response),
557
/* paned : left=notebook ; right=description */
559
paned = gtk_hpaned_new ();
560
gtk_container_set_border_width (GTK_CONTAINER (paned), 12);
561
gtk_container_add (GTK_CONTAINER (GTK_DIALOG (browser->dialog)->vbox),
563
gtk_widget_show (paned);
565
/* left = vbox : the list and the search entry */
567
vbox = gtk_vbox_new (FALSE, 6);
568
gtk_paned_pack1 (GTK_PANED (paned), vbox, FALSE, TRUE);
569
gtk_widget_show (vbox);
571
browser->count_label = gtk_label_new ("0 Plug-In Interfaces");
572
gtk_misc_set_alignment (GTK_MISC (browser->count_label), 0.0, 0.5);
573
gtk_box_pack_start (GTK_BOX (vbox), browser->count_label, FALSE, FALSE, 0);
574
gtk_widget_show (browser->count_label);
576
/* left = notebook */
578
notebook = gtk_notebook_new ();
579
gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);
581
/* list : list in a scrolled_win */
582
list_store = gtk_list_store_new (LIST_N_COLUMNS,
589
list_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (list_store));
590
g_object_unref (list_store);
592
browser->list_view = GTK_TREE_VIEW (list_view);
594
renderer = gtk_cell_renderer_text_new ();
595
column = gtk_tree_view_column_new_with_attributes (_("Name"),
597
"text", LIST_NAME_COLUMN,
599
gtk_tree_view_column_set_sort_column_id (column, LIST_NAME_COLUMN);
600
gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);
602
renderer = gtk_cell_renderer_text_new ();
603
column = gtk_tree_view_column_new_with_attributes (_("Insertion Date"),
605
"text", LIST_DATE_COLUMN,
607
gtk_tree_view_column_set_sort_column_id (column, LIST_DATE_COLUMN);
608
gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);
610
renderer = gtk_cell_renderer_text_new ();
611
column = gtk_tree_view_column_new_with_attributes (_("Menu Path"),
613
"text", LIST_PATH_COLUMN,
615
gtk_tree_view_column_set_sort_column_id (column, LIST_PATH_COLUMN);
616
gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);
618
renderer = gtk_cell_renderer_text_new ();
619
column = gtk_tree_view_column_new_with_attributes (_("Image Types"),
622
LIST_IMAGE_TYPES_COLUMN,
624
gtk_tree_view_column_set_sort_column_id (column, LIST_IMAGE_TYPES_COLUMN);
625
gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);
627
swindow = gtk_scrolled_window_new (NULL, NULL);
628
gtk_container_set_border_width (GTK_CONTAINER (swindow), 2);
629
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow),
631
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
632
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
634
gtk_widget_set_size_request (list_view, DBL_LIST_WIDTH, DBL_HEIGHT);
636
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
637
gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
639
g_signal_connect (selection, "changed",
640
G_CALLBACK (browser_list_selection_changed),
643
label = gtk_label_new (_("List View"));
644
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), swindow, label);
645
gtk_container_add (GTK_CONTAINER (swindow), list_view);
646
gtk_widget_show (list_view);
647
gtk_widget_show (swindow);
649
/* notebook->ctree */
650
tree_store = gtk_tree_store_new (LIST_N_COLUMNS,
657
tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (tree_store));
658
g_object_unref (tree_store);
660
browser->tree_view = GTK_TREE_VIEW (tree_view);
662
renderer = gtk_cell_renderer_text_new ();
663
column = gtk_tree_view_column_new_with_attributes (_("Menu Path/Name"),
666
TREE_PATH_NAME_COLUMN,
668
gtk_tree_view_column_set_sort_column_id (column, TREE_PATH_NAME_COLUMN);
669
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
671
renderer = gtk_cell_renderer_text_new ();
672
column = gtk_tree_view_column_new_with_attributes (_("Insertion Date"),
677
gtk_tree_view_column_set_sort_column_id (column, TREE_DATE_COLUMN);
678
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
680
renderer = gtk_cell_renderer_text_new ();
681
column = gtk_tree_view_column_new_with_attributes (_("Image Types"),
684
TREE_IMAGE_TYPES_COLUMN,
686
gtk_tree_view_column_set_sort_column_id (column, TREE_IMAGE_TYPES_COLUMN);
687
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
689
swindow = gtk_scrolled_window_new (NULL, NULL);
690
gtk_container_set_border_width (GTK_CONTAINER (swindow), 2);
691
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow),
693
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
694
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
695
gtk_widget_set_size_request (tree_view, DBL_LIST_WIDTH, DBL_HEIGHT);
697
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
698
gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
700
g_signal_connect (selection, "changed",
701
G_CALLBACK (browser_tree_selection_changed),
704
label = gtk_label_new (_("Tree View"));
705
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), swindow, label);
706
gtk_container_add (GTK_CONTAINER (swindow), tree_view);
708
gtk_widget_show (tree_view);
709
gtk_widget_show (swindow);
710
gtk_widget_show (notebook);
712
/* search entry & details button */
714
hbox = gtk_hbox_new (FALSE, 6);
715
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
716
gtk_widget_show (hbox);
718
label = gtk_label_new_with_mnemonic (_("_Search:"));
719
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
720
gtk_widget_show (label);
722
browser->search_entry = gtk_entry_new ();
723
gtk_entry_set_activates_default (GTK_ENTRY (browser->search_entry), TRUE);
724
gtk_box_pack_start (GTK_BOX (hbox), browser->search_entry, TRUE, TRUE, 0);
725
gtk_widget_show (browser->search_entry);
727
gtk_label_set_mnemonic_widget (GTK_LABEL (label), browser->search_entry);
729
/* right = description */
731
browser->proc_box = gimp_proc_box_new ();
732
gtk_widget_set_size_request (browser->proc_box,
733
DBL_WIDTH - DBL_LIST_WIDTH, -1);
734
gtk_paned_pack2 (GTK_PANED (paned), browser->proc_box, TRUE, TRUE);
735
gtk_widget_show (browser->proc_box);
737
/* now build the list */
738
browser_dialog_response (NULL, GTK_RESPONSE_OK, browser);
740
gtk_widget_show (browser->dialog);
742
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store), &iter))
743
gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view)),
746
gtk_widget_grab_focus (browser->search_entry);
748
return browser->dialog;
752
browser_dialog_response (GtkWidget *widget,
754
PluginBrowser *browser)
756
const gchar *search_text = NULL;
760
case GTK_RESPONSE_OK:
761
search_text = gtk_entry_get_text (GTK_ENTRY (browser->search_entry));
762
get_plugin_info (browser, search_text);
766
gtk_widget_destroy (browser->dialog);
773
browser_list_selection_changed (GtkTreeSelection *selection,
774
PluginBrowser *browser)
781
g_return_if_fail (browser != NULL);
783
if (gtk_tree_selection_get_selected (selection, &model, &iter))
785
gtk_tree_model_get (model, &iter,
786
LIST_PINFO_COLUMN, &pinfo,
787
LIST_PATH_COLUMN, &mpath,
791
if (!pinfo || !mpath)
794
model = gtk_tree_view_get_model (browser->tree_view);
796
if (find_existing_mpath (model, mpath, &iter))
798
GtkTreeSelection *tree_selection;
799
GtkTreePath *tree_path;
801
tree_path = gtk_tree_model_get_path (model, &iter);
802
gtk_tree_view_expand_to_path (browser->tree_view, tree_path);
803
tree_selection = gtk_tree_view_get_selection (browser->tree_view);
805
g_signal_handlers_block_by_func (tree_selection,
806
browser_tree_selection_changed,
808
gtk_tree_selection_select_iter (tree_selection, &iter);
809
g_signal_handlers_unblock_by_func (tree_selection,
810
browser_tree_selection_changed,
813
gtk_tree_view_scroll_to_cell (browser->tree_view,
819
g_warning ("Failed to find node in tree");
824
browser_show_plugin (browser, pinfo);
828
browser_tree_selection_changed (GtkTreeSelection *selection,
829
PluginBrowser *browser)
835
gboolean valid, found;
837
g_return_if_fail (browser != NULL);
839
if (gtk_tree_selection_get_selected (selection, &model, &iter))
841
gtk_tree_model_get (model, &iter,
842
TREE_PINFO_COLUMN, &pinfo,
843
TREE_MPATH_COLUMN, &mpath,
847
if (!pinfo || !mpath)
850
/* Get the first iter in the list */
851
model = gtk_tree_view_get_model (browser->list_view);
852
valid = gtk_tree_model_get_iter_first (model, &iter);
857
/* Walk through the list, reading each row */
860
gtk_tree_model_get (model, &iter,
861
LIST_PATH_COLUMN, &picked_mpath,
863
if (picked_mpath && !strcmp (mpath, picked_mpath))
868
g_free (picked_mpath);
869
valid = gtk_tree_model_iter_next (model, &iter);
875
GtkTreeSelection *list_selection;
876
GtkTreePath *tree_path;
878
tree_path = gtk_tree_model_get_path (model, &iter);
879
list_selection = gtk_tree_view_get_selection (browser->list_view);
881
g_signal_handlers_block_by_func (list_selection,
882
browser_list_selection_changed,
884
gtk_tree_selection_select_iter (list_selection, &iter);
885
g_signal_handlers_unblock_by_func (list_selection,
886
browser_list_selection_changed,
889
gtk_tree_view_scroll_to_cell (browser->list_view,
895
g_warning ("Failed to find node in list");
898
browser_show_plugin (browser, pinfo);
902
browser_show_plugin (PluginBrowser *browser,
907
gchar *author = NULL;
908
gchar *copyright = NULL;
910
GimpPDBProcType type = 0;
912
gint n_return_vals = 0;
913
GimpParamDef *params = NULL;
914
GimpParamDef *return_vals = NULL;
916
g_return_if_fail (browser != NULL);
917
g_return_if_fail (pinfo != NULL);
919
gimp_procedural_db_proc_info (pinfo->realname,
931
gimp_proc_box_set_widget (browser->proc_box,
932
gimp_proc_view_new (pinfo->realname,
951
gimp_destroy_paramdefs (params, n_params);
952
gimp_destroy_paramdefs (return_vals, n_return_vals);