plugin-browser.c 29.1 KB
Newer Older
1
2
3
4
5
6
7
/*
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * This is a plug-in for the GIMP.
 *
 * Copyright (C) 1999 Andy Thomas  alt@picnic.demon.co.uk
 *
8
 * Note some portions of the UI comes from the dbbrowser plugin.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 * 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 2 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

24
25
#include "config.h"

26
27
#include <string.h>
#include <time.h>
28
29
30

#include <gtk/gtk.h>

31
32
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
33

34
#include "gimpbrowser.h"
35
36
#include "gimpprocview.h"

37
#include "libgimp/stdplugins-intl.h"
38

39

40
41
42
43
44
#define DBL_LIST_WIDTH  250
#define DBL_WIDTH       (DBL_LIST_WIDTH + 400)
#define DBL_HEIGHT      250


45
46
enum
{
47
48
49
50
51
52
  LIST_COLUMN_NAME,
  LIST_COLUMN_DATE,
  LIST_COLUMN_PATH,
  LIST_COLUMN_IMAGE_TYPES,
  LIST_COLUMN_PINFO,
  N_LIST_COLUMNS
53
54
55
56
};

enum
{
57
58
59
60
61
62
  TREE_COLUMN_PATH_NAME,
  TREE_COLUMN_DATE,
  TREE_COLUMN_IMAGE_TYPES,
  TREE_COLUMN_MPATH,
  TREE_COLUMN_PINFO,
  N_TREE_OLUMNS
63
64
};

65
typedef struct
66
{
67
68
  GtkWidget   *dialog;

69
  GtkWidget   *browser;
70

71
72
  GtkTreeView *list_view;
  GtkTreeView *tree_view;
73
} PluginBrowser;
74
75
76
77
78
79
80
81
82
83
84

typedef struct
{
  gchar *menu;
  gchar *accel;
  gchar *prog;
  gchar *types;
  gchar *realname;
  gint  instime;
} PInfo;

85
86
87
88

/* Declare some local functions.
 */
static void   query      (void);
89
90
91
92
93
static void   run        (const gchar      *name,
                          gint              nparams,
                          const GimpParam  *param,
                          gint             *nreturn_vals,
                          GimpParam       **return_vals);
94

95

96
97
98
99
100
101
102
103
104
105
static GtkWidget * browser_dialog_new             (void);
static void        browser_dialog_response        (GtkWidget        *widget,
                                                   gint              response_id,
                                                   PluginBrowser    *browser);
static void        browser_list_selection_changed (GtkTreeSelection *selection,
                                                   PluginBrowser    *browser);
static void        browser_tree_selection_changed (GtkTreeSelection *selection,
                                                   PluginBrowser    *browser);
static void        browser_show_plugin            (PluginBrowser    *browser,
                                                   PInfo            *pinfo);
106

107
108
109
static gboolean    find_existing_mpath            (GtkTreeModel     *model,
                                                   gchar            *mpath,
                                                   GtkTreeIter      *return_iter);
110

111
112


113
static PluginBrowser *browser = NULL;
114

115
GimpPlugInInfo PLUG_IN_INFO =
116
{
117
118
119
120
  NULL,  /* init_proc  */
  NULL,  /* quit_proc  */
  query, /* query_proc */
  run,   /* run_proc   */
121
122
123
124
125
};


MAIN ()

126

127
static void
128
query (void)
129
{
130
  static GimpParamDef args[] =
131
  {
132
    { GIMP_PDB_INT32, "run_mode", "Interactive, [non-interactive]" }
133
  };
134

135
  gimp_install_procedure ("plug_in_plug_in_details",
Sven Neumann's avatar
Sven Neumann committed
136
137
138
                          "Displays plug-in details",
                          "Allows to browse the plug-in menus system. You can "
                          "search for plug-in names, sort by name or menu "
139
                          "location and you can view a tree representation "
Sven Neumann's avatar
Sven Neumann committed
140
141
142
                          "of the plug-in menus. Can also be of help to find "
                          "where new plug-ins have installed themselves in "
                          "the menus.",
143
144
145
                          "Andy Thomas",
                          "Andy Thomas",
                          "1999",
Sven Neumann's avatar
Sven Neumann committed
146
                          N_("_Plug-In Browser"),
147
                          "",
148
                          GIMP_PLUGIN,
149
                          G_N_ELEMENTS (args), 0,
150
                          args, NULL);
151
152

  gimp_plugin_menu_register ("plug_in_plug_in_details",
153
                             "<Toolbox>/Xtns/Extensions");
154
  gimp_plugin_icon_register ("plug_in_plug_in_details",
155
                             GIMP_ICON_TYPE_STOCK_ID, GIMP_STOCK_PLUGIN);
156
157
158
}

static void
159
160
161
162
163
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
164
{
165
  static GimpParam  values[2];
166
  GimpRunMode       run_mode;
167
168
169
170

  run_mode = param[0].data.d_int32;

  *nreturn_vals = 1;
171
  *return_vals  = values;
172

173
174
  values[0].type          = GIMP_PDB_STATUS;
  values[0].data.d_status = GIMP_PDB_CALLING_ERROR;
175

176
  INIT_I18N ();
177

178
  if (strcmp (name, "plug_in_plug_in_details") == 0)
179
    {
180
181
      GtkWidget *plugin_dialog;

182
183
      *nreturn_vals = 1;

184
      values[0].data.d_status = GIMP_PDB_SUCCESS;
185

186
      plugin_dialog = browser_dialog_new ();
187

188
189
190
191
      gtk_main ();
    }
}

192
#if 0
193
static void
194
pinfo_free (gpointer p)
195
{
196
  PInfo *pinfo = p;
197

198
199
200
201
202
203
  g_free (pinfo->menu);
  g_free (pinfo->accel);
  g_free (pinfo->prog);
  g_free (pinfo->types);
  g_free (pinfo->realname);
  g_free (pinfo);
204
}
205
#endif
206

207
208
209
210
211
212
static gboolean
find_existing_mpath_helper (GtkTreeModel *model,
                            GtkTreeIter  *iter,
                            GtkTreePath  *path,
                            gchar        *mpath,
                            GtkTreeIter  *return_iter)
213
{
214
215
216
217
  do
    {
      GtkTreeIter  child;
      gchar       *picked_mpath;
218

219
      gtk_tree_model_get (model, iter,
220
                          TREE_COLUMN_MPATH, &picked_mpath,
221
                          -1);
222
223
224
225
226
227
228

      if (! strcmp (mpath, picked_mpath))
        {
          *return_iter = *iter;
          g_free (picked_mpath);
          return TRUE;
        }
229
230
231
232

      if (gtk_tree_model_iter_children (model, &child, iter))
        {
          gtk_tree_path_down (path);
233

234
          if (find_existing_mpath_helper (model, &child, path,
235
236
237
238
239
240
                                          mpath, return_iter))
            {
              g_free (picked_mpath);
              return TRUE;
            }

241
242
          gtk_tree_path_up (path);
        }
243

244
245
246
247
      gtk_tree_path_next (path);
      g_free (picked_mpath);
    }
  while (gtk_tree_model_iter_next (model, iter));
248

249
250
251
252
253
254
255
256
257
258
  return FALSE;
}

static gboolean
find_existing_mpath (GtkTreeModel *model,
                     gchar        *mpath,
                     GtkTreeIter  *return_iter)
{
  GtkTreePath *path;
  GtkTreeIter  parent;
259
  gboolean     found;
260
261

  path = gtk_tree_path_new_first ();
262

263
  if (! gtk_tree_model_get_iter (model, &parent, path))
264
    {
265
266
      gtk_tree_path_free (path);
      return FALSE;
267
268
    }

269
270
  found = find_existing_mpath_helper (model, &parent, path,
                                      mpath, return_iter);
271
  gtk_tree_path_free (path);
272
273

  return found;
274
275
276
}

static void
277
278
279
get_parent (PluginBrowser *browser,
            gchar         *mpath,
            GtkTreeIter   *parent)
280
281
282
283
284
285
286
287
288
289
{
  GtkTreeIter   last_parent;
  gchar        *tmp_ptr;
  gchar        *str_ptr;
  gchar        *leaf_ptr;
  GtkTreeStore *tree_store;

  if (mpath == NULL)
    return;

290
  tree_store = GTK_TREE_STORE (gtk_tree_view_get_model (browser->tree_view));
291
292
293
294
295

  /* Lookup for existing mpath */
  if (find_existing_mpath (GTK_TREE_MODEL (tree_store), mpath, parent))
    return;

296
  /* Next one up */
297
  tmp_ptr = g_strdup (mpath);
298

299
  str_ptr = strrchr (tmp_ptr,'/');
300

301
  if (str_ptr == NULL)
302
303
    {
      leaf_ptr = mpath;
304
305
      gtk_tree_store_append (tree_store, parent, NULL);
      gtk_tree_store_set (tree_store, parent,
306
307
                          TREE_COLUMN_MPATH,     mpath,
                          TREE_COLUMN_PATH_NAME, mpath,
308
                          -1);
309
310
311
    }
  else
    {
312
      leaf_ptr = g_strdup (str_ptr + 1);
313

314
      *str_ptr = '\0';
315

316
      get_parent (browser, tmp_ptr, &last_parent);
317
318
      gtk_tree_store_append (tree_store, parent, &last_parent);
      gtk_tree_store_set (tree_store, parent,
319
320
                          TREE_COLUMN_MPATH,     mpath,
                          TREE_COLUMN_PATH_NAME, leaf_ptr,
321
                          -1);
322
323
324
325
    }
}

static void
326
327
328
329
330
331
insert_into_tree_view (PluginBrowser *browser,
                       gchar         *name,
                       gchar         *xtimestr,
                       gchar         *menu_str,
                       gchar         *types_str,
                       PInfo         *pinfo)
332
{
333
334
335
336
337
  gchar        *labels[3];
  gchar        *str_ptr;
  gchar        *tmp_ptr;
  gchar        *leaf_ptr;
  GtkTreeIter   parent, iter;
338
  GtkTreeStore *tree_store;
339
340
341
342

  /* Find all nodes */
  /* Last one is the leaf part */

343
344
345
346
347
  tmp_ptr = g_strdup (menu_str);

  str_ptr = strrchr (tmp_ptr, '/');

  if (str_ptr == NULL)
348
349
    return; /* No node */

350
  leaf_ptr = g_strdup (str_ptr + 1);
351

352
  *str_ptr = '\0';
353
354
355

  /*   printf("inserting %s...\n",menu_str); */

356
  get_parent (browser, tmp_ptr, &parent);
357
358
359

  /* Last was a leaf */
  /*   printf("found leaf %s parent = %p\n",leaf_ptr,parent); */
360
361
362
363
  labels[0] = g_strdup (name);
  labels[1] = g_strdup (xtimestr);
  labels[2] = g_strdup (types_str);

364
  tree_store = GTK_TREE_STORE (gtk_tree_view_get_model (browser->tree_view));
365
366
  gtk_tree_store_append (tree_store, &iter, &parent);
  gtk_tree_store_set (tree_store, &iter,
367
368
369
370
371
                      TREE_COLUMN_MPATH,       menu_str,
                      TREE_COLUMN_PATH_NAME,   name,
                      TREE_COLUMN_IMAGE_TYPES, types_str,
                      TREE_COLUMN_DATE,        xtimestr,
                      TREE_COLUMN_PINFO,       pinfo,
372
                      -1);
373
374
375
}

static void
376
377
378
browser_search (GimpBrowser   *gimp_browser,
                gint           search_type,
                PluginBrowser *browser)
379
{
380
  const gchar  *search_text;
381
382
  GimpParam    *return_vals;
  gint          nreturn_vals;
383
384
  gint          num_plugins;
  gchar        *str;
385
386
  GtkListStore *list_store;
  GtkTreeStore *tree_store;
387

388
389
  search_text = gtk_entry_get_text (GTK_ENTRY (gimp_browser->search_entry));

390
  if (! search_text)
391
392
    search_text = "";

393
394
  gimp_browser_show_message (GIMP_BROWSER (browser->browser),
                             _("Searching by name - please wait"));
395

396
397
  return_vals = gimp_run_procedure ("gimp_plugins_query",
                                    &nreturn_vals,
398
                                    GIMP_PDB_STRING, search_text,
Sven Neumann's avatar
Sven Neumann committed
399
                                    GIMP_PDB_END);
400

Sven Neumann's avatar
Sven Neumann committed
401
  if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
402
403
404
    num_plugins = return_vals[1].data.d_int32;
  else
    num_plugins = 0;
405

406
407
408
409
  if (num_plugins == 1)
    str = g_strdup (_("1 Plug-In Interface"));
  else
    str = g_strdup_printf (_("%d Plug-In Interfaces"), num_plugins);
410

411
  gtk_label_set_text (GTK_LABEL (gimp_browser->count_label), str);
412
  g_free (str);
413

414
415
  list_store = GTK_LIST_STORE (gtk_tree_view_get_model (browser->list_view));
  gtk_list_store_clear (list_store);
416

417
418
  tree_store = GTK_TREE_STORE (gtk_tree_view_get_model (browser->tree_view));
  gtk_tree_store_clear (tree_store);
419

420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
  if (num_plugins > 0)
    {
      GtkTreeSelection  *sel;
      GtkTreeIter        iter;
      gchar            **menu_strs;
      gchar            **accel_strs;
      gchar            **prog_strs;
      gchar            **types_strs;
      gchar            **realname_strs;
      gint              *time_ints;
      gint               i;

      menu_strs     = return_vals[2].data.d_stringarray;
      accel_strs    = return_vals[4].data.d_stringarray;
      prog_strs     = return_vals[6].data.d_stringarray;
      types_strs    = return_vals[8].data.d_stringarray;
      time_ints     = return_vals[10].data.d_int32array;
      realname_strs = return_vals[12].data.d_stringarray;

      for (i = 0; i < num_plugins; i++)
440
441
442
443
444
445
446
447
        {
          PInfo     *pinfo;
          gchar     *name;
          gchar      xtimestr[50];
          struct tm *x;
          time_t     tx;
          int        ret;

448
          name = strrchr (menu_strs[i], '/');
449
450
451
452

          if (name)
            name = name + 1;
          else
453
            name = menu_strs[i];
454

455
          tx = time_ints[i];
456
457
          if (tx)
            {
458
              const gchar *format = "%c";  /* gcc workaround to avoid warning */
459
              gchar       *utf8;
460

461
              x = localtime (&tx);
462
              ret = strftime (xtimestr, sizeof (xtimestr), format, x);
463
              xtimestr[ret] = 0;
464
465
466
467
468
469
470

              if ((utf8 = g_locale_to_utf8 (xtimestr, -1, NULL, NULL, NULL)))
                {
                  strncpy (xtimestr, utf8, sizeof (xtimestr));
                  xtimestr[sizeof (xtimestr) - 1] = 0;
                  g_free (utf8);
                }
471
472
            }
          else
473
474
475
            {
              strcpy (xtimestr, "");
            }
476

477
478
479
480
481
482
483
484
          pinfo = g_new0 (PInfo, 1);

          pinfo->menu     = g_strdup (menu_strs[i]);
          pinfo->accel    = g_strdup (accel_strs[i]);
          pinfo->prog     = g_strdup (prog_strs[i]);
          pinfo->types    = g_strdup (types_strs[i]);
          pinfo->instime  = time_ints[i];
          pinfo->realname = g_strdup (realname_strs[i]);
485
486
487

          gtk_list_store_append (list_store, &iter);
          gtk_list_store_set (list_store, &iter,
488
489
490
491
492
                              LIST_COLUMN_NAME,        name,
                              LIST_COLUMN_DATE,        xtimestr,
                              LIST_COLUMN_PATH,        menu_strs[i],
                              LIST_COLUMN_IMAGE_TYPES, types_strs[i],
                              LIST_COLUMN_PINFO,       pinfo,
493
494
495
                              -1);

          /* Now do the tree view.... */
496
          insert_into_tree_view (browser,
497
498
                                 name,
                                 xtimestr,
499
500
                                 menu_strs[i],
                                 types_strs[i],
501
502
                                 pinfo);
        }
503
504
505
506

      gtk_tree_view_columns_autosize (GTK_TREE_VIEW (browser->list_view));
      gtk_tree_view_columns_autosize (GTK_TREE_VIEW (browser->tree_view));

507
      gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store),
508
                                            LIST_COLUMN_NAME,
509
                                            GTK_SORT_ASCENDING);
510
      gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (tree_store),
511
                                            TREE_COLUMN_PATH_NAME,
512
                                            GTK_SORT_ASCENDING);
513

514
      sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->list_view));
515

516
517
518
519
520
521
      gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store),
                                     &iter);
      gtk_tree_selection_select_iter (sel, &iter);
    }
  else
    {
522
523
      gimp_browser_show_message (GIMP_BROWSER (browser->browser),
                                 _("No matches"));
524
    }
525
526

  gimp_destroy_params (return_vals, nreturn_vals);
527
}
528
529

static GtkWidget *
530
browser_dialog_new (void)
531
{
532
533
  GtkWidget         *label, *notebook;
  GtkWidget         *scrolled_window;
534
535
536
537
538
539
540
541
  GtkListStore      *list_store;
  GtkTreeStore      *tree_store;
  GtkWidget         *list_view;
  GtkWidget         *tree_view;
  GtkTreeViewColumn *column;
  GtkCellRenderer   *renderer;
  GtkTreeSelection  *selection;
  GtkTreeIter        iter;
542

543
  gimp_ui_init ("plugindetails", FALSE);
544

545
  browser = g_new0 (PluginBrowser, 1);
546

547
548
549
550
  browser->dialog = gimp_dialog_new (_("Plug-In Browser"), "plugindetails",
                                     NULL, 0,
                                     gimp_standard_help_func,
                                     "plug-in-plug-in-details",
551

552
                                     GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
553

554
                                     NULL);
555

556
  g_signal_connect (browser->dialog, "response",
557
                    G_CALLBACK (browser_dialog_response),
558
                    browser);
559

560
561
  browser->browser = gimp_browser_new ();
  gtk_container_set_border_width (GTK_CONTAINER (browser->browser), 12);
562
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (browser->dialog)->vbox),
563
564
                     browser->browser);
  gtk_widget_show (browser->browser);
565

566
567
  g_signal_connect (browser->browser, "search",
                    G_CALLBACK (browser_search),
568
                    browser);
569

570
571
  /* left = notebook */

572
  notebook = gtk_notebook_new ();
573
574
  gtk_box_pack_start (GTK_BOX (GIMP_BROWSER (browser->browser)->left_vbox),
                      notebook, TRUE, TRUE, 0);
575
576

  /* list : list in a scrolled_win */
577
  list_store = gtk_list_store_new (N_LIST_COLUMNS,
578
579
580
581
582
583
584
585
586
                                   G_TYPE_STRING,
                                   G_TYPE_STRING,
                                   G_TYPE_STRING,
                                   G_TYPE_STRING,
                                   G_TYPE_POINTER);

  list_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (list_store));
  g_object_unref (list_store);

587
  browser->list_view = GTK_TREE_VIEW (list_view);
588
589

  renderer = gtk_cell_renderer_text_new ();
590
591
  column = gtk_tree_view_column_new_with_attributes (_("Name"),
                                                     renderer,
592
                                                     "text", LIST_COLUMN_NAME,
593
                                                     NULL);
594
  gtk_tree_view_column_set_sort_column_id  (column, LIST_COLUMN_NAME);
595
596
597
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

  renderer = gtk_cell_renderer_text_new ();
598
  column = gtk_tree_view_column_new_with_attributes (_("Insertion Date"),
599
                                                     renderer,
600
                                                     "text", LIST_COLUMN_DATE,
601
                                                     NULL);
602
  gtk_tree_view_column_set_sort_column_id  (column, LIST_COLUMN_DATE);
603
604
605
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

  renderer = gtk_cell_renderer_text_new ();
606
  column = gtk_tree_view_column_new_with_attributes (_("Menu Path"),
607
                                                     renderer,
608
                                                     "text", LIST_COLUMN_PATH,
609
                                                     NULL);
610
  gtk_tree_view_column_set_sort_column_id  (column, LIST_COLUMN_PATH);
611
612
613
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

  renderer = gtk_cell_renderer_text_new ();
614
  column = gtk_tree_view_column_new_with_attributes (_("Image Types"),
615
616
                                                     renderer,
                                                     "text",
617
                                                     LIST_COLUMN_IMAGE_TYPES,
618
                                                     NULL);
619
  gtk_tree_view_column_set_sort_column_id  (column, LIST_COLUMN_IMAGE_TYPES);
620
621
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

622
623
624
  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
  gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 2);
  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
625
                                       GTK_SHADOW_IN);
626
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
627
628
629
                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

  gtk_widget_set_size_request (list_view, DBL_LIST_WIDTH, DBL_HEIGHT);
630

631
632
  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
  gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
633

634
  g_signal_connect (selection, "changed",
635
                    G_CALLBACK (browser_list_selection_changed),
636
                    browser);
637

638
  label = gtk_label_new (_("List View"));
639
640
  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled_window, label);
  gtk_container_add (GTK_CONTAINER (scrolled_window), list_view);
641
  gtk_widget_show (list_view);
642
  gtk_widget_show (scrolled_window);
643
644

  /* notebook->ctree */
645
  tree_store = gtk_tree_store_new (N_LIST_COLUMNS,
646
647
648
649
650
651
652
653
654
                                   G_TYPE_STRING,
                                   G_TYPE_STRING,
                                   G_TYPE_STRING,
                                   G_TYPE_STRING,
                                   G_TYPE_POINTER);

  tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (tree_store));
  g_object_unref (tree_store);

655
  browser->tree_view = GTK_TREE_VIEW (tree_view);
656
657

  renderer = gtk_cell_renderer_text_new ();
658
  column = gtk_tree_view_column_new_with_attributes (_("Menu Path/Name"),
659
660
                                                     renderer,
                                                     "text",
661
                                                     TREE_COLUMN_PATH_NAME,
662
                                                     NULL);
663
  gtk_tree_view_column_set_sort_column_id  (column, TREE_COLUMN_PATH_NAME);
664
665
666
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);

  renderer = gtk_cell_renderer_text_new ();
667
  column = gtk_tree_view_column_new_with_attributes (_("Insertion Date"),
668
669
                                                     renderer,
                                                     "text",
670
                                                     TREE_COLUMN_DATE,
671
                                                     NULL);
672
  gtk_tree_view_column_set_sort_column_id  (column, TREE_COLUMN_DATE);
673
674
675
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);

  renderer = gtk_cell_renderer_text_new ();
676
  column = gtk_tree_view_column_new_with_attributes (_("Image Types"),
677
678
                                                     renderer,
                                                     "text",
679
                                                     TREE_COLUMN_IMAGE_TYPES,
680
                                                     NULL);
681
  gtk_tree_view_column_set_sort_column_id  (column, TREE_COLUMN_IMAGE_TYPES);
682
683
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);

684
685
686
  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
  gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 2);
  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
687
                                       GTK_SHADOW_IN);
688
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
689
690
691
692
693
                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_widget_set_size_request (tree_view, DBL_LIST_WIDTH, DBL_HEIGHT);

  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
  gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
694

695
  g_signal_connect (selection, "changed",
696
                    G_CALLBACK (browser_tree_selection_changed),
697
                    browser);
698

699
  label = gtk_label_new (_("Tree View"));
700
701
  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled_window, label);
  gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
702

703
  gtk_widget_show (tree_view);
704
  gtk_widget_show (scrolled_window);
705
  gtk_widget_show (notebook);
706

707
  gtk_widget_set_size_request (GIMP_BROWSER (browser->browser)->right_vbox->parent->parent,
708
                               DBL_WIDTH - DBL_LIST_WIDTH, -1);
709

710
  /* now build the list */
711
  browser_search (GIMP_BROWSER (browser->browser), 0, browser);
712

713
  gtk_widget_show (browser->dialog);
714

715
  if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store), &iter))
716
717
    gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view)),
                                    &iter);
718

719
  return browser->dialog;
720
}
721
722
723
724
725
726

static void
browser_dialog_response (GtkWidget     *widget,
                         gint           response_id,
                         PluginBrowser *browser)
{
727
728
729
730
  gtk_widget_destroy (browser->dialog);
  gtk_main_quit ();
}

731
732
733
734
735
736
737
738
739
740
741
742
743
744
static void
browser_list_selection_changed (GtkTreeSelection *selection,
                                PluginBrowser    *browser)
{
  PInfo        *pinfo = NULL;
  GtkTreeIter   iter;
  GtkTreeModel *model;
  gchar        *mpath = NULL;

  g_return_if_fail (browser != NULL);

  if (gtk_tree_selection_get_selected (selection, &model, &iter))
    {
      gtk_tree_model_get (model, &iter,
745
746
                          LIST_COLUMN_PINFO, &pinfo,
                          LIST_COLUMN_PATH,  &mpath,
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
                          -1);
    }

  if (!pinfo || !mpath)
    return;

  model = gtk_tree_view_get_model (browser->tree_view);

  if (find_existing_mpath (model, mpath, &iter))
    {
      GtkTreeSelection *tree_selection;
      GtkTreePath      *tree_path;

      tree_path = gtk_tree_model_get_path (model, &iter);
      gtk_tree_view_expand_to_path (browser->tree_view, tree_path);
      tree_selection = gtk_tree_view_get_selection (browser->tree_view);

      g_signal_handlers_block_by_func (tree_selection,
                                       browser_tree_selection_changed,
                                       browser);
      gtk_tree_selection_select_iter (tree_selection, &iter);
      g_signal_handlers_unblock_by_func (tree_selection,
                                         browser_tree_selection_changed,
                                         browser);

      gtk_tree_view_scroll_to_cell (browser->tree_view,
                                    tree_path, NULL,
                                    TRUE, 0.5, 0.0);
    }
  else
    {
      g_warning ("Failed to find node in tree");
    }

  g_free (mpath);

  browser_show_plugin (browser, pinfo);
}

static void
browser_tree_selection_changed (GtkTreeSelection *selection,
                                PluginBrowser    *browser)
{
  PInfo        *pinfo = NULL;
  GtkTreeIter   iter;
  GtkTreeModel *model;
  gchar        *mpath = NULL;
  gboolean      valid, found;

  g_return_if_fail (browser != NULL);

  if (gtk_tree_selection_get_selected (selection, &model, &iter))
    {
      gtk_tree_model_get (model, &iter,
801
802
                          TREE_COLUMN_PINFO, &pinfo,
                          TREE_COLUMN_MPATH, &mpath,
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
                          -1);
    }

  if (!pinfo || !mpath)
    return;

  /* Get the first iter in the list */
  model = gtk_tree_view_get_model (browser->list_view);
  valid = gtk_tree_model_get_iter_first (model, &iter);
  found = FALSE;

  while (valid)
    {
      /* Walk through the list, reading each row */
      gchar *picked_mpath;

      gtk_tree_model_get (model, &iter,
820
                          LIST_COLUMN_PATH, &picked_mpath,
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
                          -1);
      if (picked_mpath && !strcmp (mpath, picked_mpath))
        {
          found = TRUE;
          break;
        }
      g_free (picked_mpath);
      valid = gtk_tree_model_iter_next (model, &iter);
    }
  g_free (mpath);

  if (found)
    {
      GtkTreeSelection *list_selection;
      GtkTreePath      *tree_path;

      tree_path = gtk_tree_model_get_path (model, &iter);
      list_selection = gtk_tree_view_get_selection (browser->list_view);

      g_signal_handlers_block_by_func (list_selection,
                                       browser_list_selection_changed,
                                       browser);
      gtk_tree_selection_select_iter (list_selection, &iter);
      g_signal_handlers_unblock_by_func (list_selection,
                                         browser_list_selection_changed,
                                         browser);

      gtk_tree_view_scroll_to_cell (browser->list_view,
                                    tree_path, NULL,
                                    TRUE, 0.5, 0.0);
    }
  else
    {
      g_warning ("Failed to find node in list");
    }

  browser_show_plugin (browser, pinfo);
}

static void
browser_show_plugin (PluginBrowser *browser,
                     PInfo         *pinfo)
{
864
865
866
867
868
869
870
871
872
873
  gchar           *blurb         = NULL;
  gchar           *help          = NULL;
  gchar           *author        = NULL;
  gchar           *copyright     = NULL;
  gchar           *date          = NULL;
  GimpPDBProcType  type          = 0;
  gint             n_params      = 0;
  gint             n_return_vals = 0;
  GimpParamDef    *params        = NULL;
  GimpParamDef    *return_vals   = NULL;
874
875
876
877
878

  g_return_if_fail (browser != NULL);
  g_return_if_fail (pinfo != NULL);

  gimp_procedural_db_proc_info (pinfo->realname,
879
880
881
882
883
884
885
886
887
888
                                &blurb,
                                &help,
                                &author,
                                &copyright,
                                &date,
                                &type,
                                &n_params,
                                &n_return_vals,
                                &params,
                                &return_vals);
889

890
891
892
893
894
895
896
897
898
899
900
901
902
  gimp_browser_set_widget (GIMP_BROWSER (browser->browser),
                           gimp_proc_view_new (pinfo->realname,
                                               pinfo->menu,
                                               blurb,
                                               help,
                                               author,
                                               copyright,
                                               date,
                                               type,
                                               n_params,
                                               n_return_vals,
                                               params,
                                               return_vals));
903
904
905
906
907
908
909
910
911

  g_free (blurb);
  g_free (help);
  g_free (author);
  g_free (copyright);
  g_free (date);

  gimp_destroy_paramdefs (params,      n_params);
  gimp_destroy_paramdefs (return_vals, n_return_vals);
912
}