plugin-browser.c 35.9 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
28
29
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
30
31
32

#include <gtk/gtk.h>

33
34
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
35

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

38

39
40
41
#define DBL_LIST_WIDTH  250
#define DBL_WIDTH       (DBL_LIST_WIDTH + 300)
#define DBL_HEIGHT      200
42

43
typedef struct
44
{
45
46
47
48
49
50
51
52
53
54
  GtkTreeView *list_view;
  GtkTreeView *tree_view;
  GtkWidget   *dlg;
  GtkWidget   *search_entry;
  GtkWidget   *descr_scroll;
  GtkWidget   *info_table;
  GtkWidget   *paned;
  GtkWidget   *info_align;
  gint         num_plugins;
  gboolean     details_showing;
55
56
57
58
59
60
61
62
63
64
65
66
} PDesc;

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

67
68
69
70
71
72
73
74
75
enum
{
  LIST_NAME_COLUMN,
  LIST_DATE_COLUMN,
  LIST_PATH_COLUMN,
  LIST_IMAGE_TYPES_COLUMN,
  LIST_PINFO_COLUMN,
  LIST_N_COLUMNS
};
76

77
78
79
80
81
82
83
84
85
enum
{
  TREE_PATH_NAME_COLUMN,
  TREE_DATE_COLUMN,
  TREE_IMAGE_TYPES_COLUMN,
  TREE_MPATH_COLUMN,
  TREE_PINFO_COLUMN,
  TREE_N_COLUMNS
};
86
87
88
89

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

96

97
static GtkWidget * gimp_plugin_desc           (void);
98

99
100
101
static gboolean    find_existing_mpath        (GtkTreeModel     *model,
                                               gchar            *mpath,
                                               GtkTreeIter      *return_iter);
102

103
static void        list_store_select_callback (GtkTreeSelection *selection,
104
                                               PDesc            *pdesc);
105
static void        tree_store_select_callback (GtkTreeSelection *selection,
106
                                               PDesc            *pdesc);
107

108
109
static void        procedure_general_select_callback (PDesc *pdesc,
                                                      PInfo *pinfo);
110
111
112
113
114
115
116
117
118
119
120


static gchar *proc_type_str[] =
{
  N_("Internal GIMP procedure"),
  N_("GIMP Plug-In"),
  N_("GIMP Extension"),
  N_("Temporary Procedure")
};

static PDesc *plugindesc = NULL;
121

122
GimpPlugInInfo PLUG_IN_INFO =
123
{
124
125
126
127
  NULL,  /* init_proc  */
  NULL,  /* quit_proc  */
  query, /* query_proc */
  run,   /* run_proc   */
128
129
130
131
132
};


MAIN ()

133

134
static void
135
query (void)
136
{
137
  static GimpParamDef args[] =
138
  {
139
    { GIMP_PDB_INT32, "run_mode", "Interactive, [non-interactive]" }
140
  };
141

142
  gimp_install_procedure ("plug_in_plug_in_details",
Marc Lehmann's avatar
Marc Lehmann committed
143
                          "Displays plugin details",
144
                          "Helps browse the plugin menus system. You can "
145
146
147
148
149
                          "search for plugin names, sort by name or menu "
                          "location and you can view a tree representation "
                          "of the plugin menus. Can also be of help to find "
                          "where new plugins have installed themselves in "
                          "the menuing system",
150
151
152
                          "Andy Thomas",
                          "Andy Thomas",
                          "1999",
153
154
                          N_("<Toolbox>/Xtns/_Plugin Details"),
                          "",
155
                          GIMP_PLUGIN,
156
                          G_N_ELEMENTS (args), 0,
157
158
159
160
                          args, NULL);
}

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

  run_mode = param[0].data.d_int32;

  *nreturn_vals = 1;
173
  *return_vals  = values;
174

175
176
  values[0].type          = GIMP_PDB_STATUS;
  values[0].data.d_status = GIMP_PDB_CALLING_ERROR;
177

178
  INIT_I18N ();
179

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

184
185
      *nreturn_vals = 1;

186
      values[0].data.d_status = GIMP_PDB_SUCCESS;
187

188
189
      plugin_dialog = gimp_plugin_desc ();

190
191
192
193
      gtk_main ();
    }
}

194
195
/* Bit of a fiddle but sorta has the effect I want... */

196
static void
197
details_callback (GtkWidget *widget,
198
                  PDesc     *pdesc)
199
{
200
201
202
  GtkLabel         *lab = GTK_LABEL (GTK_BIN (widget)->child);
  GtkTreeSelection *list_selection;
  GtkTreeIter       iter;
203

204
  /* This is a lame hack:
205
206
207
208
209
210
     We add the description on the right on the first details_callback.
     Otherwise the window reacts quite weird on resizes */
  if (pdesc->descr_scroll == NULL)
    {
      pdesc->descr_scroll = gtk_scrolled_window_new (NULL, NULL);
      gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (pdesc->descr_scroll),
211
212
                                      GTK_POLICY_ALWAYS,
                                      GTK_POLICY_ALWAYS);
213
      gtk_widget_set_size_request (pdesc->descr_scroll,
214
                                   DBL_WIDTH - DBL_LIST_WIDTH, -1);
215
      gtk_paned_pack2 (GTK_PANED (pdesc->paned), pdesc->descr_scroll,
216
217
218
219
                       FALSE, TRUE);
      list_selection = gtk_tree_view_get_selection (pdesc->list_view);
      if (gtk_tree_selection_get_selected (list_selection, NULL, &iter))
        list_store_select_callback (list_selection, pdesc);
220
221
    }

222
  if (pdesc->details_showing == FALSE)
223
    {
224
225
      GTK_PANED (pdesc->paned)->child1_resize = FALSE;
      gtk_label_set_text (lab, _("Details <<"));
226
227
228
229
230
      gtk_widget_show (pdesc->descr_scroll);
      pdesc->details_showing = TRUE;
    }
  else
    {
231
232
      GTK_PANED (pdesc->paned)->child1_resize = TRUE;
      GTK_PANED (pdesc->paned)->child2_resize = TRUE;
Hans Breuer's avatar
Hans Breuer committed
233

234
      gtk_label_set_text (lab, _("Details >>"));
235
      gtk_widget_hide (pdesc->descr_scroll);
236
      gtk_paned_set_position (GTK_PANED (pdesc->paned),
237
                              GTK_PANED (pdesc->paned)->child1->allocation.width);
238
239
240
241
242
      pdesc->details_showing = FALSE;
    }
}

static gchar *
243
format_menu_path (gchar *s)
244
{
245
246
  gchar **str_array;
  gchar  *newstr = NULL;
247

248
  if (!s)
249
250
    return s;

251
  str_array = g_strsplit (s, "/", 0);
252

253
  newstr = g_strjoinv ("->", str_array);
254

255
  g_strfreev (str_array);
256
257
258
259

  return newstr;
}

260
static void
261
procedure_general_select_callback (PDesc *pdesc,
262
                                   PInfo *pinfo)
263
{
264
  gchar           *selected_proc_blurb;
265
  gchar           *selected_proc_help;
266
267
268
  gchar           *selected_proc_author;
  gchar           *selected_proc_copyright;
  gchar           *selected_proc_date;
269
  GimpPDBProcType  selected_proc_type;
270
271
272
273
  gint             selected_nparams;
  gint             selected_nreturn_vals;
  GimpParamDef    *selected_params;
  GimpParamDef    *selected_return_vals;
274
275
276
277
278
279
280
281
  GtkWidget       *label;
  GtkWidget       *help;
  GtkWidget       *text_view;
  GtkTextBuffer   *text_buffer;
  GtkWidget       *old_table;
  GtkWidget       *old_align;
  gint             table_row = 0;
  gchar           *str;
282
283
284
285
286
287
288
289
290
291
292
293
294
  GtkWidget       *separator;
  GtkWidget       *entry;

#define ADD_SEPARATOR                                                         \
G_STMT_START                                                                  \
{                                                                             \
  separator = gtk_hseparator_new ();                                          \
  gtk_table_attach (GTK_TABLE (pdesc->info_table), separator,                 \
                    0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6);  \
  gtk_widget_show (separator);                                                \
  table_row++;                                                                \
}                                                                             \
G_STMT_END
295

296
297
  g_return_if_fail (pdesc != NULL);
  g_return_if_fail (pinfo != NULL);
298

299
  if (pdesc->descr_scroll == NULL)
300
    return;
301

302
303
304
  selected_proc_blurb     = NULL;
  selected_proc_help      = NULL;
  selected_proc_author    = NULL;
305
  selected_proc_copyright = NULL;
306
307
308
309
310
311
  selected_proc_date      = NULL;
  selected_proc_type      = 0;
  selected_nparams        = 0;
  selected_nreturn_vals   = 0;
  selected_params         = NULL;
  selected_return_vals    = NULL;
312

313
  gimp_procedural_db_proc_info (pinfo->realname,
314
315
316
317
318
319
320
321
                                &selected_proc_blurb,
                                &selected_proc_help,
                                &selected_proc_author,
                                &selected_proc_copyright,
                                &selected_proc_date,
                                &selected_proc_type,
                                &selected_nparams, &selected_nreturn_vals,
                                &selected_params,  &selected_return_vals);
322
323
324
325

  old_table = pdesc->info_table;
  old_align = pdesc->info_align;

326
  pdesc->info_table = gtk_table_new (10, 5, FALSE);
327
328
  pdesc->info_align = gtk_alignment_new (0.5, 0.5, 0, 0);

329
330
  gtk_table_set_col_spacings (GTK_TABLE (pdesc->info_table), 6);
  gtk_table_set_row_spacing (GTK_TABLE (pdesc->info_table), 0, 2);
331
332
333

  /* Number of plugins */

Sven Neumann's avatar
Sven Neumann committed
334
  str = g_strdup_printf (_("Number of Plugin Interfaces: %d"),
335
                         pdesc->num_plugins);
336
337
  label = gtk_label_new (str);
  g_free (str);
338
339
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  gtk_table_attach (GTK_TABLE (pdesc->info_table), label,
340
                    0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0);
341
  gtk_widget_show (label);
342
343
  table_row++;

344
  ADD_SEPARATOR;
345
346
347

  /* menu path */

348
  label = gtk_label_new (format_menu_path (pinfo->menu));
349
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
350
351
352
  gimp_table_attach_aligned (GTK_TABLE (pdesc->info_table), 0, table_row,
                             _("Menu Path:"), 1.0, 0.5,
                             label, 3, FALSE);
353
354
  table_row++;

355
  ADD_SEPARATOR;
356
357
358

  /* show the name */

359
360
361
362
363
364
  entry = gtk_entry_new ();
  gtk_entry_set_text (GTK_ENTRY (entry), pinfo->realname);
  gtk_editable_set_editable (GTK_EDITABLE (entry), FALSE);
  gimp_table_attach_aligned (GTK_TABLE (pdesc->info_table), 0, table_row,
                             _("Name:"), 1.0, 0.5,
                             entry, 3, FALSE);
365
366
  table_row++;

367
  ADD_SEPARATOR;
368
369
370

  /* show the description */

371
  label = gtk_label_new (selected_proc_blurb);
372
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
373
374
375
  gimp_table_attach_aligned (GTK_TABLE (pdesc->info_table), 0, table_row,
                             _("Blurb:"), 1.0, 0.5,
                             label, 3, FALSE);
376
377
  table_row++;

378
  ADD_SEPARATOR;
379
380

  /* show the help */
381
  if (selected_proc_help && (strlen (selected_proc_help) > 1))
382
383
384
385
    {
      help = gtk_table_new (2, 2, FALSE);
      gtk_table_set_row_spacing (GTK_TABLE (help), 0, 2);
      gtk_table_set_col_spacing (GTK_TABLE (help), 0, 2);
386
387
388
      gimp_table_attach_aligned (GTK_TABLE (pdesc->info_table), 0, table_row,
                                 _("Help:"), 1.0, 0.5,
                                 help, 3, FALSE);
389
      table_row++;
390

Hans Breuer's avatar
Hans Breuer committed
391
392
393
394
      text_buffer = gtk_text_buffer_new  (NULL);
      gtk_text_buffer_set_text (text_buffer, selected_proc_help, -1);

      text_view = gtk_text_view_new_with_buffer (text_buffer);
395
      g_object_unref (text_buffer);
Hans Breuer's avatar
Hans Breuer committed
396
397
398
399

      gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE);
      gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view), GTK_WRAP_WORD);

400
      gtk_widget_set_size_request (text_view, -1, 60);
Hans Breuer's avatar
Hans Breuer committed
401
      gtk_table_attach (GTK_TABLE (help), text_view, 0, 1, 0, 1,
402
403
                        GTK_EXPAND | GTK_SHRINK | GTK_FILL,
                        GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
Hans Breuer's avatar
Hans Breuer committed
404
      gtk_widget_show (text_view);
405

406
      ADD_SEPARATOR;
407
408
409
410
    }

  /* show the type */

411
  label = gtk_label_new (gettext (proc_type_str[selected_proc_type]));
412
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
413
414
415
  gimp_table_attach_aligned (GTK_TABLE (pdesc->info_table), 0, table_row,
                             _("Type:"), 1.0, 0.5,
                             label, 3, FALSE);
416
417
  table_row++;

418
  ADD_SEPARATOR;
419
420
421

  /* Remove old and replace with new */

422
423
  if (old_table)
    gtk_widget_destroy (old_table);
424

425
426
  if (old_align)
    gtk_widget_destroy (old_align);
427
428
429

  gtk_container_add (GTK_CONTAINER (pdesc->info_align),pdesc->info_table);

430
  gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (pdesc->descr_scroll),
431
                                         pdesc->info_align);
432

433
434
435
436
437
438
  gtk_widget_show (pdesc->info_table);
  gtk_widget_show (pdesc->info_align);

  if (selected_proc_blurb)
    g_free (selected_proc_blurb);
  if (selected_proc_help)
439
    g_free (selected_proc_help);
440
441
442
443
444
445
446
447
448
449
  if (selected_proc_author)
    g_free (selected_proc_author);
  if (selected_proc_copyright)
    g_free (selected_proc_copyright);
  if (selected_proc_date)
    g_free (selected_proc_date);
  if (selected_params)
    g_free (selected_params);
  if (selected_return_vals)
    g_free (selected_return_vals);
450
451
}

452
static void
453
454
list_store_select_callback (GtkTreeSelection *selection,
                            PDesc            *pdesc)
455
{
456
457
458
459
  PInfo        *pinfo = NULL;
  GtkTreeIter   iter;
  GtkTreeModel *model;
  gchar        *mpath = NULL;
460

461
  g_return_if_fail (pdesc != NULL);
462

463
464
465
466
467
468
469
  if (gtk_tree_selection_get_selected (selection, &model, &iter))
    {
      gtk_tree_model_get (model, &iter, 
                          LIST_PINFO_COLUMN, &pinfo,
                          LIST_PATH_COLUMN,  &mpath,
                          -1);
    }
470

471
  if (!pinfo || !mpath)
472
    return;
473

474
475
  model = gtk_tree_view_get_model (pdesc->tree_view);
  if (find_existing_mpath (model, mpath, &iter))
476
    {
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
      GtkTreeSelection *tree_selection;
      GtkTreePath *tree_path;

      tree_path = gtk_tree_model_get_path (model, &iter);
      gtk_tree_view_expand_to_path (pdesc->tree_view, tree_path);
      tree_selection = gtk_tree_view_get_selection (pdesc->tree_view);
      g_signal_handlers_block_by_func (tree_selection,
                                       G_CALLBACK (tree_store_select_callback),
                                       pdesc);
      gtk_tree_selection_select_iter (tree_selection, &iter);
      g_signal_handlers_unblock_by_func (tree_selection,
                                         G_CALLBACK (tree_store_select_callback),
                                         pdesc);
      gtk_tree_view_scroll_to_cell (pdesc->tree_view,
                                    tree_path, NULL,
                                    TRUE, 0.5, 0.0);
493
494
495
    }
  else
    {
496
      g_warning ("Failed to find node in tree");
497
    }
498
  g_free (mpath);
499
  procedure_general_select_callback (pdesc, pinfo);
500
501
}

502
static void
503
504
tree_store_select_callback (GtkTreeSelection *selection,
                            PDesc            *pdesc)
505
{
506
507
508
509
510
511
  PInfo        *pinfo = NULL;
  GtkTreeIter   iter;
  GtkTreeModel *model;
  gchar        *mpath = NULL;
  gboolean      valid, found;

512
  g_return_if_fail (pdesc != NULL);
513
514

  if (gtk_tree_selection_get_selected (selection, &model, &iter))
515
    {
516
517
      gtk_tree_model_get (model, &iter, 
                          TREE_PINFO_COLUMN, &pinfo,
Manish Singh's avatar
Manish Singh committed
518
                          TREE_MPATH_COLUMN, &mpath,
519
                          -1);
520
    }
521

522
  if (!pinfo || !mpath)
523
    return;
524

525
526
527
528
  /* Get the first iter in the list */
  model = gtk_tree_view_get_model (pdesc->list_view);
  valid = gtk_tree_model_get_iter_first (model, &iter);
  found = FALSE;
529

530
531
532
533
  while (valid)
    {
      /* Walk through the list, reading each row */
      gchar *picked_mpath;
534

535
536
537
538
      gtk_tree_model_get (model, &iter, 
                          LIST_PATH_COLUMN, &picked_mpath,
                          -1);
      if (picked_mpath && !strcmp (mpath, picked_mpath))
539
540
541
542
        {
          found = TRUE;
          break;
        }
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
      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 (pdesc->list_view);
      g_signal_handlers_block_by_func (list_selection,
                                       G_CALLBACK (list_store_select_callback),
                                       pdesc);
      gtk_tree_selection_select_iter (list_selection, &iter);
      g_signal_handlers_unblock_by_func (list_selection,
                                         G_CALLBACK (list_store_select_callback),
                                         pdesc);
      gtk_tree_view_scroll_to_cell (pdesc->list_view,
                                    tree_path, NULL,
                                    TRUE, 0.5, 0.0);
    }
  else
    {
      g_warning ("Failed to find node in list");
    }
570

571
  procedure_general_select_callback (pdesc, pinfo);
572
573
574
}

static void
575
pinfo_free (gpointer p)
576
{
577
  PInfo *pinfo = p;
578

579
580
581
582
583
584
  g_free (pinfo->menu);
  g_free (pinfo->accel);
  g_free (pinfo->prog);
  g_free (pinfo->types);
  g_free (pinfo->realname);
  g_free (pinfo);
585
586
}

587
588
589
590
591
592
static gboolean
find_existing_mpath_helper (GtkTreeModel *model,
                            GtkTreeIter  *iter,
                            GtkTreePath  *path,
                            gchar        *mpath,
                            GtkTreeIter  *return_iter)
593
{
594
595
596
597
  do
    {
      GtkTreeIter  child;
      gchar       *picked_mpath;
598

599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
      gtk_tree_model_get (model, iter, 
                          TREE_MPATH_COLUMN, &picked_mpath,
                          -1);
      if (!strcmp(mpath, picked_mpath))
      {
        *return_iter = *iter;
        g_free (picked_mpath);
        return TRUE;
      }

      if (gtk_tree_model_iter_children (model, &child, iter))
        {
          gtk_tree_path_down (path);
          if (find_existing_mpath_helper (model, &child, path, 
                                          mpath, return_iter)  )
          {
            g_free (picked_mpath);
            return TRUE;
          }
          gtk_tree_path_up (path);
        }
620

621
622
623
624
      gtk_tree_path_next (path);
      g_free (picked_mpath);
    }
  while (gtk_tree_model_iter_next (model, iter));
625

626
627
628
629
630
631
632
633
634
635
636
637
  return FALSE;
}

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

  path = gtk_tree_path_new_first ();
638

639
  if (gtk_tree_model_get_iter (model, &parent, path) == FALSE)
640
    {
641
642
      gtk_tree_path_free (path);
      return FALSE;
643
644
    }

645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
  return find_existing_mpath_helper (model, &parent, path,
                                     mpath, return_iter);
  gtk_tree_path_free (path);
}


static void
get_parent (PDesc       *pdesc,
            gchar       *mpath,
            GtkTreeIter *parent)
{
  GtkTreeIter   last_parent;
  gchar        *tmp_ptr;
  gchar        *str_ptr;
  gchar        *leaf_ptr;
  GtkTreeView  *tree_view;
  GtkTreeStore *tree_store;

  if (mpath == NULL)
    return;

  tree_view  = pdesc->tree_view;
  tree_store = GTK_TREE_STORE (gtk_tree_view_get_model (tree_view));

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

673
  /* Next one up */
674
  tmp_ptr = g_strdup (mpath);
675

676
  str_ptr = strrchr (tmp_ptr,'/');
677

678
  if (str_ptr == NULL)
679
680
    {
      leaf_ptr = mpath;
681
682
683
684
685
      gtk_tree_store_append (tree_store, parent, NULL);
      gtk_tree_store_set (tree_store, parent,
                          TREE_MPATH_COLUMN, mpath,
                          TREE_PATH_NAME_COLUMN, mpath,
                          -1);
686
687
688
689
    }
  else
    {
      leaf_ptr = g_strdup(str_ptr+1);
690

691
      *str_ptr = '\000';
692

693
694
695
696
697
698
      get_parent (pdesc, tmp_ptr, &last_parent);
      gtk_tree_store_append (tree_store, parent, &last_parent);
      gtk_tree_store_set (tree_store, parent,
                          TREE_MPATH_COLUMN, mpath,
                          TREE_PATH_NAME_COLUMN, leaf_ptr,
                          -1);
699
700
701
702
    }
}

static void
703
704
705
706
707
708
insert_into_tree_view (PDesc *pdesc,
                       gchar *name,
                       gchar *xtimestr,
                       gchar *menu_str,
                       gchar *types_str,
                       PInfo *pinfo)
709
{
710
711
712
713
714
  gchar        *labels[3];
  gchar        *str_ptr;
  gchar        *tmp_ptr;
  gchar        *leaf_ptr;
  GtkTreeIter   parent, iter;
715
716
  GtkTreeView  *tree_view;
  GtkTreeStore *tree_store;
717
718
719
720

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

721
722
723
724
725
  tmp_ptr = g_strdup (menu_str);

  str_ptr = strrchr (tmp_ptr, '/');

  if (str_ptr == NULL)
726
727
    return; /* No node */

728
  leaf_ptr = g_strdup (str_ptr + 1);
729
730
731
732
733

  *str_ptr = '\000';

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

734
  get_parent (pdesc, tmp_ptr, &parent);
735
736
737

  /* Last was a leaf */
  /*   printf("found leaf %s parent = %p\n",leaf_ptr,parent); */
738
739
740
741
  labels[0] = g_strdup (name);
  labels[1] = g_strdup (xtimestr);
  labels[2] = g_strdup (types_str);

742
743
744
745
746
747
748
749
750
751
  tree_view  = pdesc->tree_view;
  tree_store = GTK_TREE_STORE (gtk_tree_view_get_model (tree_view));
  gtk_tree_store_append (tree_store, &iter, &parent);
  gtk_tree_store_set (tree_store, &iter,
                      TREE_MPATH_COLUMN, menu_str,
                      TREE_PATH_NAME_COLUMN, name,
                      TREE_PINFO_COLUMN, pinfo,
                      TREE_IMAGE_TYPES_COLUMN, types_str,
                      TREE_DATE_COLUMN, xtimestr,
                      -1);
752
753
754
}

static void
755
get_plugin_info (PDesc       *pdesc,
756
                 const gchar *search_text)
757
{
758
759
760
761
762
763
764
765
766
767
768
769
770
  GimpParam    *return_vals;
  gint          nreturn_vals;
  gchar       **menu_strs;
  gchar       **accel_strs;
  gchar       **prog_strs;
  gchar       **types_strs;
  gchar       **realname_strs;
  gint         *time_ints;
  GtkTreeView  *list_view;
  GtkListStore *list_store;
  GtkTreeView  *tree_view;
  GtkTreeStore *tree_store;
  GtkTreeIter   iter;
771

772
  if (!search_text)
773
774
775
776
    search_text = "";

  return_vals = gimp_run_procedure ("gimp_plugins_query",
                                    &nreturn_vals,
777
                                    GIMP_PDB_STRING, search_text,
Sven Neumann's avatar
Sven Neumann committed
778
                                    GIMP_PDB_END);
779

Sven Neumann's avatar
Sven Neumann committed
780
  if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
781
782
783
    {
      int loop;
      pdesc->num_plugins = return_vals[1].data.d_int32;
784
785
786
787
788
789
      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;
790

791
792
793
794
795
796
797
798
      list_view  = pdesc->list_view;
      list_store = GTK_LIST_STORE (gtk_tree_view_get_model (list_view));
      gtk_list_store_clear (list_store);

      tree_view  = pdesc->tree_view;
      tree_store = GTK_TREE_STORE (gtk_tree_view_get_model (tree_view));
      gtk_tree_store_clear (tree_store);

799
      for (loop = 0; loop < return_vals[1].data.d_int32; loop++)
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
        {
          PInfo     *pinfo;
          gchar     *name;
          gchar      xtimestr[50];
          struct tm *x;
          time_t     tx;
          int        ret;

          name = strrchr (menu_strs[loop], '/');

          if (name)
            name = name + 1;
          else
            name = menu_strs[loop];

          pinfo = g_new0 (PInfo, 1);

          tx = time_ints[loop];
          if (tx)
            {
820
821
              gchar *utf8;

822
823
824
              x = localtime (&tx);
              ret = strftime (xtimestr, sizeof (xtimestr), "%c", x);
              xtimestr[ret] = 0;
825
826
827
828
829
830
831

              if ((utf8 = g_locale_to_utf8 (xtimestr, -1, NULL, NULL, NULL)))
                {
                  strncpy (xtimestr, utf8, sizeof (xtimestr));
                  xtimestr[sizeof (xtimestr) - 1] = 0;
                  g_free (utf8);
                }
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
            }
          else
            strcpy (xtimestr,"");

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

          gtk_list_store_append (list_store, &iter);
          gtk_list_store_set (list_store, &iter,
                              LIST_NAME_COLUMN,        name,
                              LIST_DATE_COLUMN,        xtimestr,
                              LIST_PATH_COLUMN,        menu_strs[loop],
                              LIST_IMAGE_TYPES_COLUMN, types_strs[loop],
                              LIST_PINFO_COLUMN,       pinfo,
                              -1);

          /* Now do the tree view.... */
          insert_into_tree_view (pdesc,
                                 name,
                                 xtimestr,
                                 menu_strs[loop],
                                 types_strs[loop],
                                 pinfo);
        }
      gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store),
                                            LIST_NAME_COLUMN,
                                            GTK_SORT_ASCENDING);
863
864
865
866
867
    }

  gimp_destroy_params (return_vals, nreturn_vals);
}

868
#if 0
869
static gint
870
date_sort (GtkCList      *clist,
871
872
           gconstpointer  ptr1,
           gconstpointer  ptr2)
873
874
875
876
877
{
  GtkCListRow *row1 = (GtkCListRow *) ptr1;
  GtkCListRow *row2 = (GtkCListRow *) ptr2;

  /* Get the data for the row */
878
879
  PInfo *row1_pinfo = row1->data;
  PInfo *row2_pinfo = row2->data;
880
881
882

  /* Want to sort on the date field */

883
  if (row2_pinfo->instime < row1_pinfo->instime)
884
    {
885
      return -1;
886
    }
887
888

  if (row2_pinfo->instime > row1_pinfo->instime)
889
    {
890
      return 1;
891
    }
892
  return 0;
893
}
894
#endif
895

896
#if 0
897
898
static void
clist_click_column (GtkCList *clist,
899
900
                    gint      column,
                    gpointer  data)
901
902
903
{
  if (column == 1)
    {
904
      gtk_clist_set_compare_func (clist, date_sort);
905
906
907
    }
  else
    {
908
      gtk_clist_set_compare_func (clist, NULL); /* Set back to default */
909
910
911
912
913
    }

  if (column == clist->sort_column)
    {
      if (clist->sort_type == GTK_SORT_ASCENDING)
914
        clist->sort_type = GTK_SORT_DESCENDING;
915
      else
916
        clist->sort_type = GTK_SORT_ASCENDING;
917
918
919
    }
  else
    gtk_clist_set_sort_column (clist, column);
920

921
922
  gtk_clist_sort (clist);
}
923
#endif
924

925
926
927
928
929
static void
dialog_response (GtkWidget *widget,
                 gint       response_id,
                 PDesc     *pdesc)
{
930
  const gchar *search_text = NULL;
931
932
933
  switch (response_id)
    {
    case GTK_RESPONSE_OK:
934
935
936
937
938
939
      if (widget != NULL)
        {
          /* The result of a button press... read entry data */
          search_text =
            gtk_entry_get_text (GTK_ENTRY (plugindesc->search_entry));
        }
940
941
942
943
944
945
946
947
948
949

        get_plugin_info (pdesc, search_text);
      break;

    default:
      gtk_widget_destroy (pdesc->dlg);
      gtk_main_quit ();
      break;
    }
}
950
951

static GtkWidget *
952
gimp_plugin_desc (void)
953
{
954
955
956
957
958
959
960
961
962
963
964
  GtkWidget         *button;
  GtkWidget         *hbox, *searchhbox, *vbox;
  GtkWidget         *label, *notebook, *swindow;
  GtkListStore      *list_store;
  GtkTreeStore      *tree_store;
  GtkWidget         *list_view;
  GtkWidget         *tree_view;
  GtkTreeViewColumn *column;
  GtkCellRenderer   *renderer;
  GtkTreeSelection  *selection;
  GtkTreeIter        iter;
965

966
  gimp_ui_init ("plugindetails", FALSE);
967

968
  plugindesc = g_new0 (PDesc, 1);
969
970

  /* the dialog box */
971
  plugindesc->dlg =
972
    gimp_dialog_new (_("Plugin Descriptions"), "plugindetails",
973
                     NULL, 0,
974
                     gimp_standard_help_func, "plug-in-plug-in-details",
975

976
977
                     GTK_STOCK_CLOSE,     GTK_RESPONSE_CLOSE,
                     _("Search by Name"), GTK_RESPONSE_OK,
978

979
                     NULL);
980
981
982

  plugindesc->details_showing = FALSE;

983
984
  g_signal_connect (plugindesc->dlg, "response",
                    G_CALLBACK (dialog_response),
985
                    plugindesc);
986

987
  /* hbox : left=notebook ; right=description */
988

989
  plugindesc->paned = hbox = gtk_hpaned_new ();
990
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (plugindesc->dlg)->vbox),
991
                      hbox, TRUE, TRUE, 0);
992
  gtk_widget_show (hbox);
993

994
  /* left = vbox : the list and the search entry */
995

996
  vbox = gtk_vbox_new (FALSE, 0);
997
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
998
999
  gtk_paned_pack1 (GTK_PANED (hbox), vbox, FALSE, FALSE);
  gtk_widget_show (vbox);
1000
1001
1002

  /* left = notebook */

1003
  notebook = gtk_notebook_new ();
1004
1005
1006
  gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);

  /* list : list in a scrolled_win */
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
  list_store = gtk_list_store_new (LIST_N_COLUMNS,
                                   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);

  plugindesc->list_view = GTK_TREE_VIEW (list_view);
1018
1019

  renderer = gtk_cell_renderer_text_new ();
1020
1021
1022
1023
1024
  column = gtk_tree_view_column_new_with_attributes (_("Name"),
                                                     renderer,
                                                     "text",
                                                     LIST_NAME_COLUMN,
                                                     NULL);
1025
1026
1027
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

  renderer = gtk_cell_renderer_text_new ();
1028
1029
1030
1031
1032
  column = gtk_tree_view_column_new_with_attributes (_("Ins Date"),
                                                     renderer,
                                                     "text",
                                                     LIST_DATE_COLUMN,
                                                     NULL);
1033
1034
1035
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

  renderer = gtk_cell_renderer_text_new ();
1036
1037
1038
1039
1040
  column = gtk_tree_view_column_new_with_attributes (_("Menu Path"),
                                                     renderer,
                                                     "text",
                                                     LIST_PATH_COLUMN,
                                                     NULL);
1041
1042
1043
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

  renderer = gtk_cell_renderer_text_new ();
1044
1045
1046
1047
1048
  column = gtk_tree_view_column_new_with_attributes (_("Image Types"),
                                                     renderer,
                                                     "text",
                                                     LIST_IMAGE_TYPES_COLUMN,
                                                     NULL);
1049
1050
1051
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

/*  g_signal_connect (plugindesc->clist, "click_column",
1052
1053
                    G_CALLBACK (clist_click_column),
                    NULL);
1054
  */
1055
1056
  swindow = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
1057
1058
1059
                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

  gtk_widget_set_size_request (list_view, DBL_LIST_WIDTH, DBL_HEIGHT);
1060

1061
1062
  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
  gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1063
  g_signal_connect (selection, "changed",
1064
                    G_CALLBACK (list_store_select_callback),
1065
                    plugindesc);
1066

1067
  label = gtk_label_new (_("List View"));
1068
  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), swindow, label);
1069
1070
  gtk_container_add (GTK_CONTAINER (swindow), list_view);
  gtk_widget_show (list_view);
1071
  gtk_widget_show (swindow);
1072
1073

  /* notebook->ctree */
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
  tree_store = gtk_tree_store_new (LIST_N_COLUMNS,
                                   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);

  plugindesc->tree_view = GTK_TREE_VIEW (tree_view);
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110

  renderer = gtk_cell_renderer_text_new ();
  column = gtk_tree_view_column_new_with_attributes (_("Menu Path/Name"), 
                                                     renderer,
                                                     "text",
                                                     TREE_PATH_NAME_COLUMN,
                                                     NULL);
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);

  renderer = gtk_cell_renderer_text_new ();
  column = gtk_tree_view_column_new_with_attributes (_("Ins Date"),
                                                     renderer,
                                                     "text",
                                                     TREE_DATE_COLUMN,
                                                     NULL);
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);

  renderer = gtk_cell_renderer_text_new ();
  column = gtk_tree_view_column_new_with_attributes (_("Image Types"),
                                                     renderer,
                                                     "text",
                                                     TREE_IMAGE_TYPES_COLUMN,
                                                     NULL);
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);

  swindow = gtk_scrolled_window_new (NULL, NULL);
1111
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
1112
1113
1114
1115
1116
                                  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);
1117
  g_signal_connect (selection, "changed",
1118
                    G_CALLBACK (tree_store_select_callback),
1119
                    plugindesc);
1120
1121

  label = gtk_label_new (_("Tree View"));
1122
  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), swindow, label);
1123
  gtk_container_add (GTK_CONTAINER (sw