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
233
      GtkWidget *p = GTK_WIDGET (pdesc->paned)->parent;
      GTK_PANED (pdesc->paned)->child1_resize = TRUE;
      GTK_PANED (pdesc->paned)->child2_resize = TRUE;
Hans Breuer's avatar
Hans Breuer committed
234

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

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

249
  if (!s)
250
251
    return s;

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

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

256
  g_strfreev (str_array);
257
258
259
260

  return newstr;
}

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

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

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

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

314
  gimp_procedural_db_proc_info (pinfo->realname,
315
316
317
318
319
320
321
322
                                &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);
323
324
325
326

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

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

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

  /* Number of plugins */

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

345
  ADD_SEPARATOR;
346
347
348

  /* menu path */

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

356
  ADD_SEPARATOR;
357
358
359

  /* show the name */

360
361
362
363
364
365
  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);
366
367
  table_row++;

368
  ADD_SEPARATOR;
369
370
371

  /* show the description */

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

379
  ADD_SEPARATOR;
380
381

  /* show the help */
382
  if (selected_proc_help && (strlen (selected_proc_help) > 1))
383
384
385
386
    {
      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);
387
388
389
      gimp_table_attach_aligned (GTK_TABLE (pdesc->info_table), 0, table_row,
                                 _("Help:"), 1.0, 0.5,
                                 help, 3, FALSE);
390
      table_row++;
391

Hans Breuer's avatar
Hans Breuer committed
392
393
394
395
      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);
396
      g_object_unref (text_buffer);
Hans Breuer's avatar
Hans Breuer committed
397
398
399
400

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

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

407
      ADD_SEPARATOR;
408
409
410
411
    }

  /* show the type */

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

419
  ADD_SEPARATOR;
420
421
422

  /* Remove old and replace with new */

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

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

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

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

434
435
436
437
438
439
  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)
440
    g_free (selected_proc_help);
441
442
443
444
445
446
447
448
449
450
  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);
451
452
}

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

462
  g_return_if_fail (pdesc != NULL);
463

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

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

475
476
  model = gtk_tree_view_get_model (pdesc->tree_view);
  if (find_existing_mpath (model, mpath, &iter))
477
    {
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
      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);
494
495
496
    }
  else
    {
497
      g_warning ("Failed to find node in tree");
498
    }
499
  g_free (mpath);
500
  procedure_general_select_callback (pdesc, pinfo);
501
502
}

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

513
  g_return_if_fail (pdesc != NULL);
514
515

  if (gtk_tree_selection_get_selected (selection, &model, &iter))
516
    {
517
518
519
520
      gtk_tree_model_get (model, &iter, 
                          TREE_PINFO_COLUMN, &pinfo,
                          TREE_MPATH_COLUMN,  &mpath,
                          -1);
521
    }
522

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

526
527
528
529
  /* 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;
530

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

536
537
538
539
      gtk_tree_model_get (model, &iter, 
                          LIST_PATH_COLUMN, &picked_mpath,
                          -1);
      if (picked_mpath && !strcmp (mpath, picked_mpath))
540
541
542
543
        {
          found = TRUE;
          break;
        }
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
570
      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");
    }
571

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

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

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

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

600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
      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);
        }
621

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

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

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

  path = gtk_tree_path_new_first ();
639

640
  if (gtk_tree_model_get_iter (model, &parent, path) == FALSE)
641
    {
642
643
      gtk_tree_path_free (path);
      return FALSE;
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
673
  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;

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

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

679
  if (str_ptr == NULL)
680
681
    {
      leaf_ptr = mpath;
682
683
684
685
686
      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);
687
688
689
690
    }
  else
    {
      leaf_ptr = g_strdup(str_ptr+1);
691

692
      *str_ptr = '\000';
693

694
695
696
697
698
699
      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);
700
701
702
703
    }
}

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

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

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

  str_ptr = strrchr (tmp_ptr, '/');

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

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

  *str_ptr = '\000';

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

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

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

743
744
745
746
747
748
749
750
751
752
  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);
753
754
755
}

static void
756
get_plugin_info (PDesc       *pdesc,
757
                 const gchar *search_text)
758
{
759
760
761
762
763
764
765
766
767
768
769
770
771
  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;
772

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

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

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

792
793
794
795
796
797
798
799
      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);

800
      for (loop = 0; loop < return_vals[1].data.d_int32; loop++)
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
        {
          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)
            {
821
822
              gchar *utf8;

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

              if ((utf8 = g_locale_to_utf8 (xtimestr, -1, NULL, NULL, NULL)))
                {
                  strncpy (xtimestr, utf8, sizeof (xtimestr));
                  xtimestr[sizeof (xtimestr) - 1] = 0;
                  g_free (utf8);
                }
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
            }
          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);
864
865
866
867
868
    }

  gimp_destroy_params (return_vals, nreturn_vals);
}

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

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

  /* Want to sort on the date field */

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

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

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

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

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

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

        get_plugin_info (pdesc, search_text);
      break;

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

static GtkWidget *
953
gimp_plugin_desc (void)
954
{
955
956
957
958
959
960
961
962
963
964
965
  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;
966

967
  gimp_ui_init ("plugindetails", FALSE);
968

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

  /* the dialog box */
972
  plugindesc->dlg =
973
    gimp_dialog_new (_("Plugin Descriptions"), "plugindetails",
974
                     NULL, 0,
975
                     gimp_standard_help_func, "filters/plugindetails.html",
976

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

980
                     NULL);
981
982
983

  plugindesc->details_showing = FALSE;

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

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

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

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

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

  /* left = notebook */

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

  /* list : list in a scrolled_win */
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
  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);
1019
1020

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

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

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

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

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

  gtk_widget_set_size_request (list_view, DBL_LIST_WIDTH, DBL_HEIGHT);
1061

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

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

  /* notebook->ctree */
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
  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);
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
1111

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

  label = gtk_label_new (_("Tree View"));
1123
  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), swindow, label);
1124
  gtk_container_add (GTK_CONTAINER (swindow), tree_view);
1125