plugin-browser.c 29 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
35
#include "gimpprocview.h"

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

38

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


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

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

64
typedef struct
65
{
66
67
  GtkWidget   *dialog;

68
  GtkWidget   *browser;
69

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

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

84
85
86
87

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

94

95
96
97
98
99
100
101
102
103
104
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);
105

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

110
111


112
static PluginBrowser *browser = NULL;
113

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


MAIN ()

125

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

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

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

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

  run_mode = param[0].data.d_int32;

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

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

175
  INIT_I18N ();
176

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

181
182
      *nreturn_vals = 1;

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

185
      plugin_dialog = browser_dialog_new ();
186

187
188
189
190
      gtk_main ();
    }
}

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

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

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

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

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

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

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

240
241
          gtk_tree_path_up (path);
        }
242

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

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

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

  path = gtk_tree_path_new_first ();
261

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

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

  return found;
273
274
275
}

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

  if (mpath == NULL)
    return;

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

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

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

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

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

313
      *str_ptr = '\0';
314

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

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

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

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

  str_ptr = strrchr (tmp_ptr, '/');

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

349
  leaf_ptr = g_strdup (str_ptr + 1);
350

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

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

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

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

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

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

387
388
  gimp_browser_show_message (GIMP_BROWSER (browser->browser),
                             _("Searching by name - please wait"));
389

390
391
  return_vals = gimp_run_procedure ("gimp_plugins_query",
                                    &nreturn_vals,
392
                                    GIMP_PDB_STRING, search_text,
Sven Neumann's avatar
Sven Neumann committed
393
                                    GIMP_PDB_END);
394

Sven Neumann's avatar
Sven Neumann committed
395
  if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
396
397
398
    num_plugins = return_vals[1].data.d_int32;
  else
    num_plugins = 0;
399

400
401
402
403
  if (num_plugins == 1)
    str = g_strdup (_("1 Plug-In Interface"));
  else
    str = g_strdup_printf (_("%d Plug-In Interfaces"), num_plugins);
404

405
  gtk_label_set_text (GTK_LABEL (gimp_browser->count_label), str);
406
  g_free (str);
407

408
409
  list_store = GTK_LIST_STORE (gtk_tree_view_get_model (browser->list_view));
  gtk_list_store_clear (list_store);
410

411
412
  tree_store = GTK_TREE_STORE (gtk_tree_view_get_model (browser->tree_view));
  gtk_tree_store_clear (tree_store);
413

414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
  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++)
434
435
436
437
438
439
440
441
        {
          PInfo     *pinfo;
          gchar     *name;
          gchar      xtimestr[50];
          struct tm *x;
          time_t     tx;
          int        ret;

442
          name = strrchr (menu_strs[i], '/');
443
444
445
446

          if (name)
            name = name + 1;
          else
447
            name = menu_strs[i];
448

449
          tx = time_ints[i];
450
451
          if (tx)
            {
452
              const gchar *format = "%c";  /* gcc workaround to avoid warning */
453
              gchar       *utf8;
454

455
              x = localtime (&tx);
456
              ret = strftime (xtimestr, sizeof (xtimestr), format, x);
457
              xtimestr[ret] = 0;
458
459
460
461
462
463
464

              if ((utf8 = g_locale_to_utf8 (xtimestr, -1, NULL, NULL, NULL)))
                {
                  strncpy (xtimestr, utf8, sizeof (xtimestr));
                  xtimestr[sizeof (xtimestr) - 1] = 0;
                  g_free (utf8);
                }
465
466
            }
          else
467
468
469
            {
              strcpy (xtimestr, "");
            }
470

471
472
473
474
475
476
477
478
          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]);
479
480
481

          gtk_list_store_append (list_store, &iter);
          gtk_list_store_set (list_store, &iter,
482
483
484
485
486
                              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,
487
488
489
                              -1);

          /* Now do the tree view.... */
490
          insert_into_tree_view (browser,
491
492
                                 name,
                                 xtimestr,
493
494
                                 menu_strs[i],
                                 types_strs[i],
495
496
                                 pinfo);
        }
497
498
499
500

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

501
      gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store),
502
                                            LIST_COLUMN_NAME,
503
                                            GTK_SORT_ASCENDING);
504
      gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (tree_store),
505
                                            TREE_COLUMN_PATH_NAME,
506
                                            GTK_SORT_ASCENDING);
507

508
      sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (browser->list_view));
509

510
511
512
513
514
515
      gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store),
                                     &iter);
      gtk_tree_selection_select_iter (sel, &iter);
    }
  else
    {
516
517
      gimp_browser_show_message (GIMP_BROWSER (browser->browser),
                                 _("No matches"));
518
    }
519
520

  gimp_destroy_params (return_vals, nreturn_vals);
521
}
522
523

static GtkWidget *
524
browser_dialog_new (void)
525
{
526
527
  GtkWidget         *label, *notebook;
  GtkWidget         *scrolled_window;
528
529
530
531
532
533
534
535
  GtkListStore      *list_store;
  GtkTreeStore      *tree_store;
  GtkWidget         *list_view;
  GtkWidget         *tree_view;
  GtkTreeViewColumn *column;
  GtkCellRenderer   *renderer;
  GtkTreeSelection  *selection;
  GtkTreeIter        iter;
536

537
  gimp_ui_init ("plugindetails", FALSE);
538

539
  browser = g_new0 (PluginBrowser, 1);
540

541
542
543
544
  browser->dialog = gimp_dialog_new (_("Plug-In Browser"), "plugindetails",
                                     NULL, 0,
                                     gimp_standard_help_func,
                                     "plug-in-plug-in-details",
545

546
                                     GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
547

548
                                     NULL);
549

550
  g_signal_connect (browser->dialog, "response",
551
                    G_CALLBACK (browser_dialog_response),
552
                    browser);
553

554
555
  browser->browser = gimp_browser_new ();
  gtk_container_set_border_width (GTK_CONTAINER (browser->browser), 12);
556
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (browser->dialog)->vbox),
557
558
                     browser->browser);
  gtk_widget_show (browser->browser);
559

560
561
  g_signal_connect (browser->browser, "search",
                    G_CALLBACK (browser_search),
562
                    browser);
563

564
565
  /* left = notebook */

566
  notebook = gtk_notebook_new ();
567
568
  gtk_box_pack_start (GTK_BOX (GIMP_BROWSER (browser->browser)->left_vbox),
                      notebook, TRUE, TRUE, 0);
569
570

  /* list : list in a scrolled_win */
571
  list_store = gtk_list_store_new (N_LIST_COLUMNS,
572
573
574
575
576
577
578
579
580
                                   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);

581
  browser->list_view = GTK_TREE_VIEW (list_view);
582
583

  renderer = gtk_cell_renderer_text_new ();
584
585
  column = gtk_tree_view_column_new_with_attributes (_("Name"),
                                                     renderer,
586
                                                     "text", LIST_COLUMN_NAME,
587
                                                     NULL);
588
  gtk_tree_view_column_set_sort_column_id  (column, LIST_COLUMN_NAME);
589
590
591
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

  renderer = gtk_cell_renderer_text_new ();
592
  column = gtk_tree_view_column_new_with_attributes (_("Insertion Date"),
593
                                                     renderer,
594
                                                     "text", LIST_COLUMN_DATE,
595
                                                     NULL);
596
  gtk_tree_view_column_set_sort_column_id  (column, LIST_COLUMN_DATE);
597
598
599
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

  renderer = gtk_cell_renderer_text_new ();
600
  column = gtk_tree_view_column_new_with_attributes (_("Menu Path"),
601
                                                     renderer,
602
                                                     "text", LIST_COLUMN_PATH,
603
                                                     NULL);
604
  gtk_tree_view_column_set_sort_column_id  (column, LIST_COLUMN_PATH);
605
606
607
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

  renderer = gtk_cell_renderer_text_new ();
608
  column = gtk_tree_view_column_new_with_attributes (_("Image Types"),
609
610
                                                     renderer,
                                                     "text",
611
                                                     LIST_COLUMN_IMAGE_TYPES,
612
                                                     NULL);
613
  gtk_tree_view_column_set_sort_column_id  (column, LIST_COLUMN_IMAGE_TYPES);
614
615
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

616
617
618
  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),
619
                                       GTK_SHADOW_IN);
620
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
621
622
623
                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

  gtk_widget_set_size_request (list_view, DBL_LIST_WIDTH, DBL_HEIGHT);
624

625
626
  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
  gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
627

628
  g_signal_connect (selection, "changed",
629
                    G_CALLBACK (browser_list_selection_changed),
630
                    browser);
631

632
  label = gtk_label_new (_("List View"));
633
634
  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled_window, label);
  gtk_container_add (GTK_CONTAINER (scrolled_window), list_view);
635
  gtk_widget_show (list_view);
636
  gtk_widget_show (scrolled_window);
637
638

  /* notebook->ctree */
639
  tree_store = gtk_tree_store_new (N_LIST_COLUMNS,
640
641
642
643
644
645
646
647
648
                                   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);

649
  browser->tree_view = GTK_TREE_VIEW (tree_view);
650
651

  renderer = gtk_cell_renderer_text_new ();
652
  column = gtk_tree_view_column_new_with_attributes (_("Menu Path/Name"),
653
654
                                                     renderer,
                                                     "text",
655
                                                     TREE_COLUMN_PATH_NAME,
656
                                                     NULL);
657
  gtk_tree_view_column_set_sort_column_id  (column, TREE_COLUMN_PATH_NAME);
658
659
660
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);

  renderer = gtk_cell_renderer_text_new ();
661
  column = gtk_tree_view_column_new_with_attributes (_("Insertion Date"),
662
663
                                                     renderer,
                                                     "text",
664
                                                     TREE_COLUMN_DATE,
665
                                                     NULL);
666
  gtk_tree_view_column_set_sort_column_id  (column, TREE_COLUMN_DATE);
667
668
669
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);

  renderer = gtk_cell_renderer_text_new ();
670
  column = gtk_tree_view_column_new_with_attributes (_("Image Types"),
671
672
                                                     renderer,
                                                     "text",
673
                                                     TREE_COLUMN_IMAGE_TYPES,
674
                                                     NULL);
675
  gtk_tree_view_column_set_sort_column_id  (column, TREE_COLUMN_IMAGE_TYPES);
676
677
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);

678
679
680
  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),
681
                                       GTK_SHADOW_IN);
682
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
683
684
685
686
687
                                  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);
688

689
  g_signal_connect (selection, "changed",
690
                    G_CALLBACK (browser_tree_selection_changed),
691
                    browser);
692

693
  label = gtk_label_new (_("Tree View"));
694
695
  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), scrolled_window, label);
  gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
696

697
  gtk_widget_show (tree_view);
698
  gtk_widget_show (scrolled_window);
699
  gtk_widget_show (notebook);
700

701
  gtk_widget_set_size_request (GIMP_BROWSER (browser->browser)->right_vbox->parent->parent,
702
                               DBL_WIDTH - DBL_LIST_WIDTH, -1);
703

704
  /* now build the list */
705
  browser_search (GIMP_BROWSER (browser->browser), "", 0, browser);
706

707
  gtk_widget_show (browser->dialog);
708

709
  if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store), &iter))
710
711
    gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view)),
                                    &iter);
712

713
  return browser->dialog;
714
}
715
716
717
718
719
720

static void
browser_dialog_response (GtkWidget     *widget,
                         gint           response_id,
                         PluginBrowser *browser)
{
721
722
723
724
  gtk_widget_destroy (browser->dialog);
  gtk_main_quit ();
}

725
726
727
728
729
730
731
732
733
734
735
736
737
738
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,
739
740
                          LIST_COLUMN_PINFO, &pinfo,
                          LIST_COLUMN_PATH,  &mpath,
741
742
743
744
745
746
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
                          -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,
795
796
                          TREE_COLUMN_PINFO, &pinfo,
                          TREE_COLUMN_MPATH, &mpath,
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
                          -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,
814
                          LIST_COLUMN_PATH, &picked_mpath,
815
816
817
818
819
820
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
                          -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)
{
858
859
860
861
862
863
864
865
866
867
  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;
868
869
870
871
872

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

  gimp_procedural_db_proc_info (pinfo->realname,
873
874
875
876
877
878
879
880
881
882
                                &blurb,
                                &help,
                                &author,
                                &copyright,
                                &date,
                                &type,
                                &n_params,
                                &n_return_vals,
                                &params,
                                &return_vals);
883

884
885
886
887
888
889
890
891
892
893
894
895
896
  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));
897
898
899
900
901
902
903
904
905

  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);
906
}