plugin-browser.c 35.5 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
98
99
100
static GtkWidget * gimp_plugin_desc           (void);
static gboolean    find_existing_mpath        (GtkTreeModel     *model,
                                               gchar            *mpath,
                                               GtkTreeIter      *return_iter);
101
static void        list_store_select_callback (GtkTreeSelection *selection,
102
                                               PDesc            *pdesc);
103
static void        tree_store_select_callback (GtkTreeSelection *selection,
104
                                               PDesc            *pdesc);
105
106
static void        procedure_general_select_callback (PDesc *pdesc,
                                                      PInfo *pinfo);
107
108
109
110
111
112
113
114
115
116
117


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

static PDesc *plugindesc = NULL;
118

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


MAIN ()

130

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

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

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

  run_mode = param[0].data.d_int32;

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

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

175
  INIT_I18N ();
176

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

181
182
      *nreturn_vals = 1;

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

185
186
      plugin_dialog = gimp_plugin_desc ();

187
188
189
190
      gtk_main ();
    }
}

191
192
/* Bit of a fiddle but sorta has the effect I want... */

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

201
  /* This is a lame hack:
202
203
204
205
206
207
     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),
208
209
                                      GTK_POLICY_ALWAYS,
                                      GTK_POLICY_ALWAYS);
210
      gtk_widget_set_size_request (pdesc->descr_scroll,
211
                                   DBL_WIDTH - DBL_LIST_WIDTH, -1);
212
      gtk_paned_pack2 (GTK_PANED (pdesc->paned), pdesc->descr_scroll,
213
214
215
216
                       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);
217
218
    }

219
  if (pdesc->details_showing == FALSE)
220
    {
221
222
      GTK_PANED (pdesc->paned)->child1_resize = FALSE;
      gtk_label_set_text (lab, _("Details <<"));
223
224
225
226
227
      gtk_widget_show (pdesc->descr_scroll);
      pdesc->details_showing = TRUE;
    }
  else
    {
228
229
230
      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
231

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

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

246
  if (!s)
247
248
    return s;

249
  str_array = g_strsplit (s, "/", 0);
250

251
  newstr = g_strjoinv ("->", str_array);
252

253
  g_strfreev (str_array);
254
255
256
257

  return newstr;
}

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

294
295
  g_return_if_fail (pdesc != NULL);
  g_return_if_fail (pinfo != NULL);
296

297
  if (pdesc->descr_scroll == NULL)
298
    return;
299

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

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

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

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

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

  /* Number of plugins */

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

342
  ADD_SEPARATOR;
343
344
345

  /* menu path */

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

353
  ADD_SEPARATOR;
354
355
356

  /* show the name */

357
358
359
360
361
362
  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);
363
364
  table_row++;

365
  ADD_SEPARATOR;
366
367
368

  /* show the description */

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

376
  ADD_SEPARATOR;
377
378

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

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

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

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

404
      ADD_SEPARATOR;
405
406
407
408
    }

  /* show the type */

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

416
  ADD_SEPARATOR;
417
418
419

  /* Remove old and replace with new */

420
421
  if (old_table)
    gtk_widget_destroy (old_table);
422

423
424
  if (old_align)
    gtk_widget_destroy (old_align);
425
426
427

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

428
  gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (pdesc->descr_scroll),
429
                                         pdesc->info_align);
430

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

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

459
  g_return_if_fail (pdesc != NULL);
460

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

469
  if (!pinfo || !mpath)
470
    return;
471

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

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

510
  g_return_if_fail (pdesc != NULL);
511
512

  if (gtk_tree_selection_get_selected (selection, &model, &iter))
513
    {
514
515
516
517
      gtk_tree_model_get (model, &iter, 
                          TREE_PINFO_COLUMN, &pinfo,
                          TREE_MPATH_COLUMN,  &mpath,
                          -1);
518
    }
519

520
  if (!pinfo || !mpath)
521
    return;
522

523
524
525
526
  /* 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;
527

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

533
534
535
536
      gtk_tree_model_get (model, &iter, 
                          LIST_PATH_COLUMN, &picked_mpath,
                          -1);
      if (picked_mpath && !strcmp (mpath, picked_mpath))
537
538
539
540
        {
          found = TRUE;
          break;
        }
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
      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");
    }
568

569
  procedure_general_select_callback (pdesc, pinfo);
570
571
572
}

static void
573
pinfo_free (gpointer p)
574
{
575
  PInfo *pinfo = p;
576

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

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

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

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

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

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

  path = gtk_tree_path_new_first ();
  if (gtk_tree_model_get_iter (model, &parent, path) == FALSE)
637
    {
638
639
      gtk_tree_path_free (path);
      return FALSE;
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
669
  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;

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

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

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

688
      *str_ptr = '\000';
689

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

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

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

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

  str_ptr = strrchr (tmp_ptr, '/');

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

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

  *str_ptr = '\000';

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

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

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

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

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

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

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

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

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

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

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

              if ((utf8 = g_locale_to_utf8 (xtimestr, -1, NULL, NULL, NULL)))
                {
                  strncpy (xtimestr, utf8, sizeof (xtimestr));
                  xtimestr[sizeof (xtimestr) - 1] = 0;
                  g_free (utf8);
                }
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
859
            }
          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);
860
861
862
863
864
    }

  gimp_destroy_params (return_vals, nreturn_vals);
}

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

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

  /* Want to sort on the date field */

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

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

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

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

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

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

        get_plugin_info (pdesc, search_text);
      break;

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

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

963
  gimp_ui_init ("plugindetails", FALSE);
964

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

  /* the dialog box */
968
  plugindesc->dlg =
969
    gimp_dialog_new (_("Plugin Descriptions"), "plugindetailsgtk2",
970
                     NULL, 0,
971
                     gimp_standard_help_func, "filters/plugindetails.html",
972

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

976
                     NULL);
977
978
979

  plugindesc->details_showing = FALSE;

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

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

986
  plugindesc->paned = hbox = gtk_hpaned_new ();
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, 0);
994
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
995
996
  gtk_paned_pack1 (GTK_PANED (hbox), vbox, FALSE, FALSE);
  gtk_widget_show (vbox);
997
998
999

  /* left = notebook */

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

  /* list : list in a scrolled_win */
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
  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));
  plugindesc->list_view =  GTK_TREE_VIEW (list_view);
  g_object_unref (G_OBJECT (list_store));

  renderer = gtk_cell_renderer_text_new ();
  column = gtk_tree_view_column_new_with_attributes (_("Name"), renderer,
                                                      "text", LIST_NAME_COLUMN,
                                                      NULL);
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

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

  renderer = gtk_cell_renderer_text_new ();
  column = gtk_tree_view_column_new_with_attributes (_("Menu Path"), renderer,
                                                      "text", LIST_PATH_COLUMN,
                                                      NULL);
  gtk_tree_view_append_column (GTK_TREE_VIEW (list_view), column);

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

/*  g_signal_connect (plugindesc->clist, "click_column",
1039
1040
                    G_CALLBACK (clist_click_column),
                    NULL);
1041
  */
1042
1043
  swindow = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
1044
1045
1046
                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

  gtk_widget_set_size_request (list_view, DBL_LIST_WIDTH, DBL_HEIGHT);
1047

1048
1049
1050
1051
  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list_view));
  gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
  g_signal_connect (G_OBJECT (selection), "changed",
                    G_CALLBACK (list_store_select_callback),
1052
                    plugindesc);
1053

1054
  label = gtk_label_new (_("List View"));
1055
  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), swindow, label);
1056
1057
  gtk_container_add (GTK_CONTAINER (swindow), list_view);
  gtk_widget_show (list_view);
1058
  gtk_widget_show (swindow);
1059
1060

  /* notebook->ctree */
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
  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));
  plugindesc->tree_view =  GTK_TREE_VIEW (tree_view);
  g_object_unref (G_OBJECT (tree_store));

  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);
1096
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
1097
1098
1099
1100
1101
1102
1103
                                  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);
  g_signal_connect (G_OBJECT (selection), "changed",
                    G_CALLBACK (tree_store_select_callback),
1104
                    plugindesc);
1105
1106

  label = gtk_label_new (_("Tree View"));
1107
  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), swindow, label);
1108
  gtk_container_add (GTK_CONTAINER (swindow), tree_view);
1109

1110
  gtk_widget_show (tree_view);
1111
1112
  gtk_widget_show (swindow);
  gtk_widget_show (notebook);
1113
1114
1115

  /* search entry & details button */

1116
  searchhbox = gtk_hbox_new (FALSE, 4);
1117
  gtk_box_pack_start (GTK_BOX (vbox),
1118
                      searchhbox, FALSE, FALSE, 0);
1119
  gtk_widget_show (searchhbox);
1120

1121
1122
  label = gtk_label_new (_("Search:"));
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1123
  gtk_box_pack_start (GTK_BOX (searchhbox),
1124
                      label, FALSE, FALSE, 0);
1125
1126
  gtk_widget_show(label);

1127
  plugindesc->search_entry = gtk_entry_new ();
1128
  gtk_box_pack_start (GTK_BOX (searchhbox),
1129
                      plugindesc->search_entry, TRUE, TRUE, 0);
1130
  gtk_widget_show (plugindesc->search_entry);
1131