plugin-browser.c 36 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
  GtkTreeView *list_view;
  GtkTreeView *tree_view;
  GtkWidget   *dlg;
  GtkWidget   *search_entry;
  GtkWidget   *descr_scroll;
  GtkWidget   *info_table;
  GtkWidget   *paned;
  gint         num_plugins;
  gboolean     details_showing;
54
55
56
57
58
59
60
61
62
63
64
65
} PDesc;

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

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

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

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

95

96
static GtkWidget * gimp_plugin_desc           (void);
97

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

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

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


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

static PDesc *plugindesc = NULL;
120

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


MAIN ()

132

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

141
  gimp_install_procedure ("plug_in_plug_in_details",
Marc Lehmann's avatar
Marc Lehmann committed
142
                          "Displays plugin details",
143
                          "Helps browse the plugin menus system. You can "
144
145
146
147
148
                          "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",
149
150
151
                          "Andy Thomas",
                          "Andy Thomas",
                          "1999",
152
                          N_("_Plugin Details"),
153
                          "",
154
                          GIMP_PLUGIN,
155
                          G_N_ELEMENTS (args), 0,
156
                          args, NULL);
157
158
159

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

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

  run_mode = param[0].data.d_int32;

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

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

182
  INIT_I18N ();
183

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

188
189
      *nreturn_vals = 1;

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

192
193
      plugin_dialog = gimp_plugin_desc ();

194
195
196
197
      gtk_main ();
    }
}

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

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

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

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

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

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

252
  if (!s)
253
254
    return s;

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

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

259
  g_strfreev (str_array);
260
261
262
263

  return newstr;
}

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

#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
297

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

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

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

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

  old_table = pdesc->info_table;

327
  pdesc->info_table = gtk_table_new (9, 5, FALSE);
328

329
  gtk_container_set_border_width (GTK_CONTAINER (pdesc->info_table), 12);
330
  gtk_table_set_col_spacings (GTK_TABLE (pdesc->info_table), 6);
331
332
  gtk_table_set_row_spacings (GTK_TABLE (pdesc->info_table), 6);

333
334
335

  /* Number of plugins */

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

346
  ADD_SEPARATOR;
347
348
349

  /* menu path */

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

357
  ADD_SEPARATOR;
358
359
360

  /* show the name */

361
362
363
  label = gtk_label_new (pinfo->realname);
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
  gtk_label_set_selectable (GTK_LABEL (label), TRUE);
364
  gimp_table_attach_aligned (GTK_TABLE (pdesc->info_table), 0, table_row,
365
366
                             _("Name:"), 0.0, 0.0,
                             label, 3, FALSE);
367
368
  table_row++;

369
  ADD_SEPARATOR;
370
371
372

  /* show the description */

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

380
  ADD_SEPARATOR;
381
382

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

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

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

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

408
      ADD_SEPARATOR;
409
410
411
412
    }

  /* show the type */

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

  /* Remove old and replace with new */

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

425
  gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (pdesc->descr_scroll),
426
                                         pdesc->info_table);
427

428
429
430
431
432
  gtk_widget_show (pdesc->info_table);

  if (selected_proc_blurb)
    g_free (selected_proc_blurb);
  if (selected_proc_help)
433
    g_free (selected_proc_help);
434
435
436
437
438
439
440
441
442
443
  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);
444
445
}

446
static void
447
448
list_store_select_callback (GtkTreeSelection *selection,
                            PDesc            *pdesc)
449
{
450
451
452
453
  PInfo        *pinfo = NULL;
  GtkTreeIter   iter;
  GtkTreeModel *model;
  gchar        *mpath = NULL;
454

455
  g_return_if_fail (pdesc != NULL);
456

457
458
  if (gtk_tree_selection_get_selected (selection, &model, &iter))
    {
459
      gtk_tree_model_get (model, &iter,
460
461
462
463
                          LIST_PINFO_COLUMN, &pinfo,
                          LIST_PATH_COLUMN,  &mpath,
                          -1);
    }
464

465
  if (!pinfo || !mpath)
466
    return;
467

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

496
static void
497
498
tree_store_select_callback (GtkTreeSelection *selection,
                            PDesc            *pdesc)
499
{
500
501
502
503
504
505
  PInfo        *pinfo = NULL;
  GtkTreeIter   iter;
  GtkTreeModel *model;
  gchar        *mpath = NULL;
  gboolean      valid, found;

506
  g_return_if_fail (pdesc != NULL);
507
508

  if (gtk_tree_selection_get_selected (selection, &model, &iter))
509
    {
510
      gtk_tree_model_get (model, &iter,
511
                          TREE_PINFO_COLUMN, &pinfo,
Manish Singh's avatar
Manish Singh committed
512
                          TREE_MPATH_COLUMN, &mpath,
513
                          -1);
514
    }
515

516
  if (!pinfo || !mpath)
517
    return;
518

519
520
521
522
  /* 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;
523

524
525
526
527
  while (valid)
    {
      /* Walk through the list, reading each row */
      gchar *picked_mpath;
528

529
      gtk_tree_model_get (model, &iter,
530
531
532
                          LIST_PATH_COLUMN, &picked_mpath,
                          -1);
      if (picked_mpath && !strcmp (mpath, picked_mpath))
533
534
535
536
        {
          found = TRUE;
          break;
        }
537
538
539
540
      g_free (picked_mpath);
      valid = gtk_tree_model_iter_next (model, &iter);
    }
  g_free (mpath);
541

542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
  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");
    }
564

565
  procedure_general_select_callback (pdesc, pinfo);
566
567
}

568
#if 0
569
static void
570
pinfo_free (gpointer p)
571
{
572
  PInfo *pinfo = p;
573

574
575
576
577
578
579
  g_free (pinfo->menu);
  g_free (pinfo->accel);
  g_free (pinfo->prog);
  g_free (pinfo->types);
  g_free (pinfo->realname);
  g_free (pinfo);
580
}
581
#endif
582

583
584
585
586
587
588
static gboolean
find_existing_mpath_helper (GtkTreeModel *model,
                            GtkTreeIter  *iter,
                            GtkTreePath  *path,
                            gchar        *mpath,
                            GtkTreeIter  *return_iter)
589
{
590
591
592
593
  do
    {
      GtkTreeIter  child;
      gchar       *picked_mpath;
594

595
      gtk_tree_model_get (model, iter,
596
597
598
599
600
601
602
603
604
605
606
607
                          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);
608
          if (find_existing_mpath_helper (model, &child, path,
609
610
611
612
613
614
615
                                          mpath, return_iter)  )
          {
            g_free (picked_mpath);
            return TRUE;
          }
          gtk_tree_path_up (path);
        }
616

617
618
619
620
      gtk_tree_path_next (path);
      g_free (picked_mpath);
    }
  while (gtk_tree_model_iter_next (model, iter));
621

622
623
624
625
626
627
628
629
630
631
632
633
  return FALSE;
}

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

  path = gtk_tree_path_new_first ();
634

635
  if (gtk_tree_model_get_iter (model, &parent, path) == FALSE)
636
    {
637
638
      gtk_tree_path_free (path);
      return FALSE;
639
640
    }

641
642
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
  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;

669
  /* Next one up */
670
  tmp_ptr = g_strdup (mpath);
671

672
  str_ptr = strrchr (tmp_ptr,'/');
673

674
  if (str_ptr == NULL)
675
676
    {
      leaf_ptr = mpath;
677
678
679
680
681
      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);
682
683
684
685
    }
  else
    {
      leaf_ptr = g_strdup(str_ptr+1);
686

687
      *str_ptr = '\000';
688

689
690
691
692
693
694
      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);
695
696
697
698
    }
}

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

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

717
718
719
720
721
  tmp_ptr = g_strdup (menu_str);

  str_ptr = strrchr (tmp_ptr, '/');

  if (str_ptr == NULL)
722
723
    return; /* No node */

724
  leaf_ptr = g_strdup (str_ptr + 1);
725
726
727
728
729

  *str_ptr = '\000';

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

730
  get_parent (pdesc, tmp_ptr, &parent);
731
732
733

  /* Last was a leaf */
  /*   printf("found leaf %s parent = %p\n",leaf_ptr,parent); */
734
735
736
737
  labels[0] = g_strdup (name);
  labels[1] = g_strdup (xtimestr);
  labels[2] = g_strdup (types_str);

738
739
740
741
742
743
744
745
746
747
  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);
748
749
750
}

static void
751
get_plugin_info (PDesc       *pdesc,
752
                 const gchar *search_text)
753
{
754
755
756
757
758
759
760
761
762
763
764
765
766
  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;
767

768
  if (!search_text)
769
770
771
772
    search_text = "";

  return_vals = gimp_run_procedure ("gimp_plugins_query",
                                    &nreturn_vals,
773
                                    GIMP_PDB_STRING, search_text,
Sven Neumann's avatar
Sven Neumann committed
774
                                    GIMP_PDB_END);
775

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

787
788
789
790
791
792
793
794
      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);

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

818
819
820
              x = localtime (&tx);
              ret = strftime (xtimestr, sizeof (xtimestr), "%c", x);
              xtimestr[ret] = 0;
821
822
823
824
825
826
827

              if ((utf8 = g_locale_to_utf8 (xtimestr, -1, NULL, NULL, NULL)))
                {
                  strncpy (xtimestr, utf8, sizeof (xtimestr));
                  xtimestr[sizeof (xtimestr) - 1] = 0;
                  g_free (utf8);
                }
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
            }
          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);
859
860
861
862
863
    }

  gimp_destroy_params (return_vals, nreturn_vals);
}

864
#if 0
865
static gint
866
date_sort (GtkCList      *clist,
867
868
           gconstpointer  ptr1,
           gconstpointer  ptr2)
869
870
871
872
873
{
  GtkCListRow *row1 = (GtkCListRow *) ptr1;
  GtkCListRow *row2 = (GtkCListRow *) ptr2;

  /* Get the data for the row */
874
875
  PInfo *row1_pinfo = row1->data;
  PInfo *row2_pinfo = row2->data;
876
877
878

  /* Want to sort on the date field */

879
  if (row2_pinfo->instime < row1_pinfo->instime)
880
    {
881
      return -1;
882
    }
883
884

  if (row2_pinfo->instime > row1_pinfo->instime)
885
    {
886
      return 1;
887
    }
888
  return 0;
889
}
890
#endif
891

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

  if (column == clist->sort_column)
    {
      if (clist->sort_type == GTK_SORT_ASCENDING)
910
        clist->sort_type = GTK_SORT_DESCENDING;
911
      else
912
        clist->sort_type = GTK_SORT_ASCENDING;
913
914
915
    }
  else
    gtk_clist_set_sort_column (clist, column);
916

917
918
  gtk_clist_sort (clist);
}
919
#endif
920

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

        get_plugin_info (pdesc, search_text);
      break;

    default:
      gtk_widget_destroy (pdesc->dlg);
      gtk_main_quit ();
      break;
    }
}
946
947

static GtkWidget *
948
gimp_plugin_desc (void)
949
{
950
951
952
953
954
955
956
957
958
959
960
  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;
961

962
  gimp_ui_init ("plugindetails", FALSE);
963

964
  plugindesc = g_new0 (PDesc, 1);
965
966

  /* the dialog box */
967
  plugindesc->dlg =
968
    gimp_dialog_new (_("Plugin Descriptions"), "plugindetails",
969
                     NULL, 0,
970
                     gimp_standard_help_func, "plug-in-plug-in-details",
971

972
973
                     GTK_STOCK_CLOSE,     GTK_RESPONSE_CLOSE,
                     _("Search by Name"), GTK_RESPONSE_OK,
974

975
                     NULL);
976
977
978

  plugindesc->details_showing = FALSE;

979
980
  g_signal_connect (plugindesc->dlg, "response",
                    G_CALLBACK (dialog_response),
981
                    plugindesc);
982

983
  /* hbox : left=notebook ; right=description */
984

985
  plugindesc->paned = hbox = gtk_hpaned_new ();
986
  gtk_container_set_border_width (GTK_CONTAINER (plugindesc->paned), 12);
987
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (plugindesc->dlg)->vbox),
988
                      hbox, TRUE, TRUE, 0);
989
  gtk_widget_show (hbox);
990

991
  /* left = vbox : the list and the search entry */
992

993
  vbox = gtk_vbox_new (FALSE, 6);
994
995
  gtk_paned_pack1 (GTK_PANED (hbox), vbox, FALSE, FALSE);
  gtk_widget_show (vbox);
996
997
998

  /* left = notebook */

999
  notebook = gtk_notebook_new ();
1000
1001
1002
  gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);

  /* list : list in a scrolled_win */
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
  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);
1014
1015

  renderer = gtk_cell_renderer_text_new ();
1016
1017
1018
1019
1020
  column = gtk_tree_view_column_new_with_attributes (_("Name"),
                                                     renderer,
                                                     "text",
                                                     LIST_NAME_COLUMN,
                                                     NULL);
1021
1022
1023
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

  renderer = gtk_cell_renderer_text_new ();
1024
1025
1026
1027
1028
  column = gtk_tree_view_column_new_with_attributes (_("Ins Date"),
                                                     renderer,
                                                     "text",
                                                     LIST_DATE_COLUMN,
                                                     NULL);
1029
1030
1031
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

  renderer = gtk_cell_renderer_text_new ();
1032
1033
1034
1035
1036
  column = gtk_tree_view_column_new_with_attributes (_("Menu Path"),
                                                     renderer,
                                                     "text",
                                                     LIST_PATH_COLUMN,
                                                     NULL);
1037
1038
1039
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

  renderer = gtk_cell_renderer_text_new ();
1040
1041
1042
1043
1044
  column = gtk_tree_view_column_new_with_attributes (_("Image Types"),
                                                     renderer,
                                                     "text",
                                                     LIST_IMAGE_TYPES_COLUMN,
                                                     NULL);
1045
1046
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

1047
  swindow = gtk_scrolled_window_new (NULL, NULL);
1048
1049
1050
  gtk_container_set_border_width (GTK_CONTAINER (swindow), 2);
  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow),
                                       GTK_SHADOW_IN);
1051
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
1052
1053
1054
                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

  gtk_widget_set_size_request (list_view, DBL_LIST_WIDTH, DBL_HEIGHT);
1055

1056
1057
  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
  gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1058
  g_signal_connect (selection, "changed",
1059
                    G_CALLBACK (list_store_select_callback),
1060
                    plugindesc);
1061

1062
  label = gtk_label_new (_("List View"));
1063
  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), swindow, label);
1064
1065
  gtk_container_add (GTK_CONTAINER (swindow), list_view);
  gtk_widget_show (list_view);