plugin-browser.c 36.1 KB
Newer Older
1
2
3
4
5
6
7
/*
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * This is a plug-in for the GIMP.
 *
 * Copyright (C) 1999 Andy Thomas  alt@picnic.demon.co.uk
 *
8
 * Note some portions of the UI comes from the dbbrowser plugin.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

24
25
#include "config.h"

26
27
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
                          N_("_Plugin Details"),
154
                          "",
155
                          GIMP_PLUGIN,
156
                          G_N_ELEMENTS (args), 0,
157
                          args, NULL);
158
159
160

  gimp_plugin_menu_register ("plug_in_plug_in_details",
                             N_("<Toolbox>/Xtns/Extensions"));
161
  gimp_plugin_icon_register ("plug_in_plug_in_details",
162
                             GIMP_ICON_TYPE_STOCK_ID, GIMP_STOCK_PLUGIN);
163
164
165
}

static void
166
167
168
169
170
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
171
{
172
  static GimpParam  values[2];
173
  GimpRunMode       run_mode;
174
175
176
177

  run_mode = param[0].data.d_int32;

  *nreturn_vals = 1;
178
  *return_vals  = values;
179

180
181
  values[0].type          = GIMP_PDB_STATUS;
  values[0].data.d_status = GIMP_PDB_CALLING_ERROR;
182

183
  INIT_I18N ();
184

185
  if (strcmp (name, "plug_in_plug_in_details") == 0)
186
    {
187
188
      GtkWidget *plugin_dialog;

189
190
      *nreturn_vals = 1;

191
      values[0].data.d_status = GIMP_PDB_SUCCESS;
192

193
194
      plugin_dialog = gimp_plugin_desc ();

195
196
197
198
      gtk_main ();
    }
}

199
200
/* Bit of a fiddle but sorta has the effect I want... */

201
static void
202
details_callback (GtkWidget *widget,
203
                  PDesc     *pdesc)
204
{
205
206
207
  GtkLabel         *lab = GTK_LABEL (GTK_BIN (widget)->child);
  GtkTreeSelection *list_selection;
  GtkTreeIter       iter;
208

209
  /* This is a lame hack:
210
211
212
213
214
215
     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),
216
217
                                      GTK_POLICY_ALWAYS,
                                      GTK_POLICY_ALWAYS);
218
      gtk_widget_set_size_request (pdesc->descr_scroll,
219
                                   DBL_WIDTH - DBL_LIST_WIDTH, -1);
220
      gtk_paned_pack2 (GTK_PANED (pdesc->paned), pdesc->descr_scroll,
221
222
223
224
                       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);
225
226
    }

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

239
      gtk_label_set_text (lab, _("Details >>"));
240
      gtk_widget_hide (pdesc->descr_scroll);
241
      gtk_paned_set_position (GTK_PANED (pdesc->paned),
242
                              GTK_PANED (pdesc->paned)->child1->allocation.width);
243
244
245
246
247
      pdesc->details_showing = FALSE;
    }
}

static gchar *
248
format_menu_path (gchar *s)
249
{
250
251
  gchar **str_array;
  gchar  *newstr = NULL;
252

253
  if (!s)
254
255
    return s;

256
  str_array = g_strsplit (s, "/", 0);
257

258
  newstr = g_strjoinv ("->", str_array);
259

260
  g_strfreev (str_array);
261
262
263
264

  return newstr;
}

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

301
302
  g_return_if_fail (pdesc != NULL);
  g_return_if_fail (pinfo != NULL);
303

304
  if (pdesc->descr_scroll == NULL)
305
    return;
306

307
308
309
  selected_proc_blurb     = NULL;
  selected_proc_help      = NULL;
  selected_proc_author    = NULL;
310
  selected_proc_copyright = NULL;
311
312
313
314
315
316
  selected_proc_date      = NULL;
  selected_proc_type      = 0;
  selected_nparams        = 0;
  selected_nreturn_vals   = 0;
  selected_params         = NULL;
  selected_return_vals    = NULL;
317

318
  gimp_procedural_db_proc_info (pinfo->realname,
319
320
321
322
323
324
325
326
                                &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);
327
328
329
330

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

331
  pdesc->info_table = gtk_table_new (10, 5, FALSE);
332
333
  pdesc->info_align = gtk_alignment_new (0.5, 0.5, 0, 0);

334
335
  gtk_table_set_col_spacings (GTK_TABLE (pdesc->info_table), 6);
  gtk_table_set_row_spacing (GTK_TABLE (pdesc->info_table), 0, 2);
336
337
338

  /* Number of plugins */

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

349
  ADD_SEPARATOR;
350
351
352

  /* menu path */

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

360
  ADD_SEPARATOR;
361
362
363

  /* show the name */

364
365
366
367
368
369
  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);
370
371
  table_row++;

372
  ADD_SEPARATOR;
373
374
375

  /* show the description */

376
  label = gtk_label_new (selected_proc_blurb);
377
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
378
379
380
  gimp_table_attach_aligned (GTK_TABLE (pdesc->info_table), 0, table_row,
                             _("Blurb:"), 1.0, 0.5,
                             label, 3, FALSE);
381
382
  table_row++;

383
  ADD_SEPARATOR;
384
385

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

Hans Breuer's avatar
Hans Breuer committed
396
397
398
399
      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);
400
      g_object_unref (text_buffer);
Hans Breuer's avatar
Hans Breuer committed
401
402
403
404

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

405
      gtk_widget_set_size_request (text_view, -1, 60);
Hans Breuer's avatar
Hans Breuer committed
406
      gtk_table_attach (GTK_TABLE (help), text_view, 0, 1, 0, 1,
407
408
                        GTK_EXPAND | GTK_SHRINK | GTK_FILL,
                        GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
Hans Breuer's avatar
Hans Breuer committed
409
      gtk_widget_show (text_view);
410

411
      ADD_SEPARATOR;
412
413
414
415
    }

  /* show the type */

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

423
  ADD_SEPARATOR;
424
425
426

  /* Remove old and replace with new */

427
428
  if (old_table)
    gtk_widget_destroy (old_table);
429

430
431
  if (old_align)
    gtk_widget_destroy (old_align);
432
433
434

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

435
  gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (pdesc->descr_scroll),
436
                                         pdesc->info_align);
437

438
439
440
441
442
443
  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)
444
    g_free (selected_proc_help);
445
446
447
448
449
450
451
452
453
454
  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);
455
456
}

457
static void
458
459
list_store_select_callback (GtkTreeSelection *selection,
                            PDesc            *pdesc)
460
{
461
462
463
464
  PInfo        *pinfo = NULL;
  GtkTreeIter   iter;
  GtkTreeModel *model;
  gchar        *mpath = NULL;
465

466
  g_return_if_fail (pdesc != NULL);
467

468
469
  if (gtk_tree_selection_get_selected (selection, &model, &iter))
    {
470
      gtk_tree_model_get (model, &iter,
471
472
473
474
                          LIST_PINFO_COLUMN, &pinfo,
                          LIST_PATH_COLUMN,  &mpath,
                          -1);
    }
475

476
  if (!pinfo || !mpath)
477
    return;
478

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

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

517
  g_return_if_fail (pdesc != NULL);
518
519

  if (gtk_tree_selection_get_selected (selection, &model, &iter))
520
    {
521
      gtk_tree_model_get (model, &iter,
522
                          TREE_PINFO_COLUMN, &pinfo,
Manish Singh's avatar
Manish Singh committed
523
                          TREE_MPATH_COLUMN, &mpath,
524
                          -1);
525
    }
526

527
  if (!pinfo || !mpath)
528
    return;
529

530
531
532
533
  /* 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;
534

535
536
537
538
  while (valid)
    {
      /* Walk through the list, reading each row */
      gchar *picked_mpath;
539

540
      gtk_tree_model_get (model, &iter,
541
542
543
                          LIST_PATH_COLUMN, &picked_mpath,
                          -1);
      if (picked_mpath && !strcmp (mpath, picked_mpath))
544
545
546
547
        {
          found = TRUE;
          break;
        }
548
549
550
551
      g_free (picked_mpath);
      valid = gtk_tree_model_iter_next (model, &iter);
    }
  g_free (mpath);
552

553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
  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");
    }
575

576
  procedure_general_select_callback (pdesc, pinfo);
577
578
}

579
#if 0
580
static void
581
pinfo_free (gpointer p)
582
{
583
  PInfo *pinfo = p;
584

585
586
587
588
589
590
  g_free (pinfo->menu);
  g_free (pinfo->accel);
  g_free (pinfo->prog);
  g_free (pinfo->types);
  g_free (pinfo->realname);
  g_free (pinfo);
591
}
592
#endif
593

594
595
596
597
598
599
static gboolean
find_existing_mpath_helper (GtkTreeModel *model,
                            GtkTreeIter  *iter,
                            GtkTreePath  *path,
                            gchar        *mpath,
                            GtkTreeIter  *return_iter)
600
{
601
602
603
604
  do
    {
      GtkTreeIter  child;
      gchar       *picked_mpath;
605

606
      gtk_tree_model_get (model, iter,
607
608
609
610
611
612
613
614
615
616
617
618
                          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);
619
          if (find_existing_mpath_helper (model, &child, path,
620
621
622
623
624
625
626
                                          mpath, return_iter)  )
          {
            g_free (picked_mpath);
            return TRUE;
          }
          gtk_tree_path_up (path);
        }
627

628
629
630
631
      gtk_tree_path_next (path);
      g_free (picked_mpath);
    }
  while (gtk_tree_model_iter_next (model, iter));
632

633
634
635
636
637
638
639
640
641
642
643
644
  return FALSE;
}

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

  path = gtk_tree_path_new_first ();
645

646
  if (gtk_tree_model_get_iter (model, &parent, path) == FALSE)
647
    {
648
649
      gtk_tree_path_free (path);
      return FALSE;
650
651
    }

652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
  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;

680
  /* Next one up */
681
  tmp_ptr = g_strdup (mpath);
682

683
  str_ptr = strrchr (tmp_ptr,'/');
684

685
  if (str_ptr == NULL)
686
687
    {
      leaf_ptr = mpath;
688
689
690
691
692
      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);
693
694
695
696
    }
  else
    {
      leaf_ptr = g_strdup(str_ptr+1);
697

698
      *str_ptr = '\000';
699

700
701
702
703
704
705
      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);
706
707
708
709
    }
}

static void
710
711
712
713
714
715
insert_into_tree_view (PDesc *pdesc,
                       gchar *name,
                       gchar *xtimestr,
                       gchar *menu_str,
                       gchar *types_str,
                       PInfo *pinfo)
716
{
717
718
719
720
721
  gchar        *labels[3];
  gchar        *str_ptr;
  gchar        *tmp_ptr;
  gchar        *leaf_ptr;
  GtkTreeIter   parent, iter;
722
723
  GtkTreeView  *tree_view;
  GtkTreeStore *tree_store;
724
725
726
727

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

728
729
730
731
732
  tmp_ptr = g_strdup (menu_str);

  str_ptr = strrchr (tmp_ptr, '/');

  if (str_ptr == NULL)
733
734
    return; /* No node */

735
  leaf_ptr = g_strdup (str_ptr + 1);
736
737
738
739
740

  *str_ptr = '\000';

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

741
  get_parent (pdesc, tmp_ptr, &parent);
742
743
744

  /* Last was a leaf */
  /*   printf("found leaf %s parent = %p\n",leaf_ptr,parent); */
745
746
747
748
  labels[0] = g_strdup (name);
  labels[1] = g_strdup (xtimestr);
  labels[2] = g_strdup (types_str);

749
750
751
752
753
754
755
756
757
758
  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);
759
760
761
}

static void
762
get_plugin_info (PDesc       *pdesc,
763
                 const gchar *search_text)
764
{
765
766
767
768
769
770
771
772
773
774
775
776
777
  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;
778

779
  if (!search_text)
780
781
782
783
    search_text = "";

  return_vals = gimp_run_procedure ("gimp_plugins_query",
                                    &nreturn_vals,
784
                                    GIMP_PDB_STRING, search_text,
Sven Neumann's avatar
Sven Neumann committed
785
                                    GIMP_PDB_END);
786

Sven Neumann's avatar
Sven Neumann committed
787
  if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
788
789
790
    {
      int loop;
      pdesc->num_plugins = return_vals[1].data.d_int32;
791
792
793
794
795
796
      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;
797

798
799
800
801
802
803
804
805
      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);

806
      for (loop = 0; loop < return_vals[1].data.d_int32; loop++)
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
        {
          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)
            {
827
828
              gchar *utf8;

829
830
831
              x = localtime (&tx);
              ret = strftime (xtimestr, sizeof (xtimestr), "%c", x);
              xtimestr[ret] = 0;
832
833
834
835
836
837
838

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

  gimp_destroy_params (return_vals, nreturn_vals);
}

875
#if 0
876
static gint
877
date_sort (GtkCList      *clist,
878
879
           gconstpointer  ptr1,
           gconstpointer  ptr2)
880
881
882
883
884
{
  GtkCListRow *row1 = (GtkCListRow *) ptr1;
  GtkCListRow *row2 = (GtkCListRow *) ptr2;

  /* Get the data for the row */
885
886
  PInfo *row1_pinfo = row1->data;
  PInfo *row2_pinfo = row2->data;
887
888
889

  /* Want to sort on the date field */

890
  if (row2_pinfo->instime < row1_pinfo->instime)
891
    {
892
      return -1;
893
    }
894
895

  if (row2_pinfo->instime > row1_pinfo->instime)
896
    {
897
      return 1;
898
    }
899
  return 0;
900
}
901
#endif
902

903
#if 0
904
905
static void
clist_click_column (GtkCList *clist,
906
907
                    gint      column,
                    gpointer  data)
908
909
910
{
  if (column == 1)
    {
911
      gtk_clist_set_compare_func (clist, date_sort);
912
913
914
    }
  else
    {
915
      gtk_clist_set_compare_func (clist, NULL); /* Set back to default */
916
917
918
919
920
    }

  if (column == clist->sort_column)
    {
      if (clist->sort_type == GTK_SORT_ASCENDING)
921
        clist->sort_type = GTK_SORT_DESCENDING;
922
      else
923
        clist->sort_type = GTK_SORT_ASCENDING;
924
925
926
    }
  else
    gtk_clist_set_sort_column (clist, column);
927

928
929
  gtk_clist_sort (clist);
}
930
#endif
931

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

        get_plugin_info (pdesc, search_text);
      break;

    default:
      gtk_widget_destroy (pdesc->dlg);
      gtk_main_quit ();
      break;
    }
}
957
958

static GtkWidget *
959
gimp_plugin_desc (void)
960
{
961
962
963
964
965
966
967
968
969
970
971
  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;
972

973
  gimp_ui_init ("plugindetails", FALSE);
974

975
  plugindesc = g_new0 (PDesc, 1);
976
977

  /* the dialog box */
978
  plugindesc->dlg =
979
    gimp_dialog_new (_("Plugin Descriptions"), "plugindetails",
980
                     NULL, 0,
981
                     gimp_standard_help_func, "plug-in-plug-in-details",
982

983
984
                     GTK_STOCK_CLOSE,     GTK_RESPONSE_CLOSE,
                     _("Search by Name"), GTK_RESPONSE_OK,
985

986
                     NULL);
987
988
989

  plugindesc->details_showing = FALSE;

990
991
  g_signal_connect (plugindesc->dlg, "response",
                    G_CALLBACK (dialog_response),
992
                    plugindesc);
993

994
  /* hbox : left=notebook ; right=description */
995

996
  plugindesc->paned = hbox = gtk_hpaned_new ();
997
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (plugindesc->dlg)->vbox),
998
                      hbox, TRUE, TRUE, 0);
999
  gtk_widget_show (hbox);
1000

1001
  /* left = vbox : the list and the search entry */
1002

1003
  vbox = gtk_vbox_new (FALSE, 0);
1004
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
1005
1006
  gtk_paned_pack1 (GTK_PANED (hbox), vbox, FALSE, FALSE);
  gtk_widget_show (vbox);
1007
1008
1009

  /* left = notebook */

1010
  notebook = gtk_notebook_new ();
1011
1012
1013
  gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);

  /* list : list in a scrolled_win */
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
  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);
1025
1026

  renderer = gtk_cell_renderer_text_new ();
1027
1028
1029
1030
1031
  column = gtk_tree_view_column_new_with_attributes (_("Name"),
                                                     renderer,
                                                     "text",
                                                     LIST_NAME_COLUMN,
                                                     NULL);
1032
1033
1034
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

  renderer = gtk_cell_renderer_text_new ();
1035
1036
1037
1038
1039
  column = gtk_tree_view_column_new_with_attributes (_("Ins Date"),
                                                     renderer,
                                                     "text",
                                                     LIST_DATE_COLUMN,
                                                     NULL);
1040
1041
1042
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

  renderer = gtk_cell_renderer_text_new ();
1043
1044
1045
1046
1047
  column = gtk_tree_view_column_new_with_attributes (_("Menu Path"),
                                                     renderer,
                                                     "text",
                                                     LIST_PATH_COLUMN,
                                                     NULL);
1048
1049
1050
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

  renderer = gtk_cell_renderer_text_new ();
1051
1052
1053
1054
1055
  column = gtk_tree_view_column_new_with_attributes (_("Image Types"),
                                                     renderer,
                                                     "text",
                                                     LIST_IMAGE_TYPES_COLUMN,
                                                     NULL);
1056
1057
1058
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

/*  g_signal_connect (plugindesc->clist, "click_column",
1059
1060
                    G_CALLBACK (clist_click_column),
                    NULL);
1061
  */
1062
1063
  swindow = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
1064
1065
1066
                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

  gtk_widget_set_size_request (list_view, DBL_LIST_WIDTH, DBL_HEIGHT);
1067

1068
1069
  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
  gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1070
  g_signal_connect (selection, "changed",
1071
                    G_CALLBACK (list_store_select_callback),
1072
                    plugindesc);
1073

1074
  label = gtk_label_new (_("List View"));
1075
  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), swindow, label);
1076
1077
  gtk_container_add (GTK_CONTAINER (swindow), list_view);
  gtk_widget_show (list_view);
1078
  gtk_widget_show (swindow);
1079
1080

  /* notebook->ctree */
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
  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));<