From 2851c0da268a21b0c0eae6975798de5ef439e87b Mon Sep 17 00:00:00 2001 From: GMT 1999 Andy Thomas Date: Thu, 4 Feb 1999 01:31:33 +0000 Subject: [PATCH] Try again to add the plugin dir & files. Thu Feb 4 00:23:26 GMT 1999 Andy Thomas Try again to add the plugin dir & files. --- ChangeLog | 4 + plug-ins/common/plugin-browser.c | 1097 ++++++++++++++++++++++++ plug-ins/common/plugindetails.c | 1097 ++++++++++++++++++++++++ plug-ins/dbbrowser/plugin-browser.c | 1097 ++++++++++++++++++++++++ plug-ins/plugindetails/.cvsignore | 6 + plug-ins/plugindetails/Makefile.am | 35 + plug-ins/plugindetails/plugindetails.c | 1097 ++++++++++++++++++++++++ 7 files changed, 4433 insertions(+) create mode 100644 plug-ins/common/plugin-browser.c create mode 100644 plug-ins/common/plugindetails.c create mode 100644 plug-ins/dbbrowser/plugin-browser.c create mode 100644 plug-ins/plugindetails/.cvsignore create mode 100644 plug-ins/plugindetails/Makefile.am create mode 100644 plug-ins/plugindetails/plugindetails.c diff --git a/ChangeLog b/ChangeLog index 2a56e1c412..34ecde93ec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +Thu Feb 4 00:23:26 GMT 1999 Andy Thomas + + Tried again to add the plugin dir & files. + Thu Feb 4 00:07:13 GMT 1999 Andy Thomas Changed:- diff --git a/plug-ins/common/plugin-browser.c b/plug-ins/common/plugin-browser.c new file mode 100644 index 0000000000..fddbe758fc --- /dev/null +++ b/plug-ins/common/plugin-browser.c @@ -0,0 +1,1097 @@ +/* + * 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 + * + * Note some portions of th UI comes from the dbbrowser plugin. + * 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. + */ + +#include +#include +#include +#include +#include +#include "gtk/gtk.h" +#include "libgimp/gimp.h" + +#define DBL_LIST_WIDTH 250 +#define DBL_WIDTH DBL_LIST_WIDTH+450 +#define DBL_HEIGHT 200 + +static char *proc_type_str[] = +{ + "Internal GIMP procedure", + "GIMP Plug-In", + "GIMP Extension", + "Temporary Procedure" +}; + + +/* Declare some local functions. + */ +static void query (void); +static void run (char *name, + int nparams, + GParam *param, + int *nreturn_vals, + GParam **return_vals); + +static GtkWidget * gimp_plugin_desc(); +static gint procedure_clist_select_callback (GtkWidget *widget, + gint row, + gint column, + GdkEventButton * bevent, + gpointer data); +static gint procedure_ctree_select_callback (GtkWidget *widget, + GtkWidget *row, + gint column, + gpointer data); + +GPlugInInfo PLUG_IN_INFO = +{ + NULL, /* init_proc */ + NULL, /* quit_proc */ + query, /* query_proc */ + run, /* run_proc */ +}; + + +MAIN () + +static void +query () +{ + static GParamDef args[] = + { + { PARAM_INT32, "run_mode", "Interactive, [non-interactive]" } + }; + + static int nargs = sizeof (args) / sizeof (args[0]); + + gimp_install_procedure ("plug_in_details", + "Displays plugin details", + "Helps browse the plugin menus system. You can 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", + "Andy Thomas", + "Andy Thomas", + "1999", + "/Xtns/Plugin Details", + "", + PROC_EXTENSION, + nargs, 0, + args, NULL); +} + +static void +run (char *name, + int nparams, + GParam *param, + int *nreturn_vals, + GParam **return_vals) +{ + static GParam values[2]; + GRunModeType run_mode; + GtkWidget * plugin_dialog; + + run_mode = param[0].data.d_int32; + + *nreturn_vals = 1; + *return_vals = values; + values[0].type = PARAM_STATUS; + values[0].data.d_status = STATUS_CALLING_ERROR; + + if (strcmp (name, "plug_in_details") == 0) + { + *nreturn_vals = 1; + + values[0].data.d_status = STATUS_SUCCESS; + + plugin_dialog = gimp_plugin_desc(); + gtk_widget_show(plugin_dialog); + gtk_main (); + gdk_flush (); + } +} + + +typedef struct +{ + GtkWidget * dlg; + GtkWidget * clist; + GtkWidget * ctree; + GtkWidget * search_entry; + GtkWidget * descr_scroll; + GtkWidget * name_button; + GtkWidget * blurb_button; + GtkWidget * scrolled_win; + GtkWidget * ctree_scrolled_win; + GtkWidget * info_table; + GtkWidget * info_align; + gint num_plugins; + gint ctree_row; + gint clist_row; + gboolean details_showing; +} PLUGINDESC,*PLUGINDESCP; + +PLUGINDESCP plugindesc = NULL; + +typedef struct +{ + gchar *menu; + gchar *accel; + gchar *prog; + gchar *types; + gchar *realname; + gint instime; +} PINFO, *PINFOP; + +static void +dialog_close_callback (GtkWidget *widget, + gpointer data) + /* end of the dialog */ +{ + PLUGINDESCP pdesc = data; + gtk_widget_destroy(pdesc->dlg); + gtk_main_quit (); +} + +static void +details_callback (GtkWidget *widget, + gpointer data) +{ + /* Show or hide the details window */ + PLUGINDESCP pdesc = data; + GtkLabel *lab = GTK_LABEL(GTK_BIN (widget)->child); + + if(pdesc->details_showing == FALSE) + { + gtk_label_set_text(lab,"Details <<<"); + gtk_widget_show (pdesc->descr_scroll); + pdesc->details_showing = TRUE; + } + else + { + gtk_label_set_text(lab,"Details >>>"); + gtk_widget_hide (pdesc->descr_scroll); + pdesc->details_showing = FALSE; + } +} + +static gchar * +format_menu_path(gchar *s) +{ + gchar ** str_array; + gchar *newstr = NULL; + + if(!s) + return s; + + str_array = g_strsplit(s,"/",0); + + newstr = g_strjoinv("->",str_array); + + g_strfreev(str_array); + + return newstr; +} + +static gint +procedure_general_select_callback (PLUGINDESCP pdesc, + PINFOP pinfo) +{ + gchar *selected_proc_blurb; + gchar *selected_proc_help; + gchar *selected_proc_author; + gchar *selected_proc_copyright; + gchar *selected_proc_date; + gint selected_proc_type; + gint selected_nparams; + gint selected_nreturn_vals; + GParamDef *selected_params; + GParamDef *selected_return_vals; + GtkWidget *label; + GtkWidget *help; + GtkWidget *text; + GtkWidget *vscrollbar; + GtkWidget *old_table; + GtkWidget *old_align; + gint table_row = 0; + + g_return_val_if_fail (pdesc != NULL, FALSE); + + g_return_val_if_fail (pinfo != NULL, FALSE); + + selected_proc_blurb = NULL; + selected_proc_help = NULL; + selected_proc_author = NULL; + selected_proc_copyright = NULL; + selected_proc_date = NULL; + selected_proc_type = 0; + selected_nparams = 0; + selected_nreturn_vals = 0; + selected_params = NULL; + selected_return_vals = NULL; + + gimp_query_procedure (pinfo->realname, + &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); + + old_table = pdesc->info_table; + old_align = pdesc->info_align; + + pdesc->info_table = gtk_table_new(10 ,5 , FALSE); + pdesc->info_align = gtk_alignment_new (0.5, 0.5, 0, 0); + + gtk_table_set_col_spacings( GTK_TABLE(pdesc->info_table), 3); + + /* Number of plugins */ + + label = gtk_label_new(g_strdup_printf(" Number of plugin interfaces :%d",pdesc->num_plugins)); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + + /* menu path */ + + label = gtk_label_new("Menu path :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 0); + gtk_widget_show(label); + + label = gtk_label_new(format_menu_path(pinfo->menu)); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + /* show the name */ + + label = gtk_label_new("Name :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + + label = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(label),pinfo->realname); + gtk_entry_set_editable(GTK_ENTRY(label), FALSE); + gtk_table_attach (GTK_TABLE(pdesc->info_table), label, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + /* show the description */ + + label = gtk_label_new("Blurb :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 0); + gtk_widget_show(label); + + label = gtk_label_new(selected_proc_blurb); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + /* show the help */ + if ((selected_proc_help) && (strlen(selected_proc_help) > 1)) + { + label = gtk_label_new("Help :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, + GTK_FILL, GTK_FILL, 3, 0); + gtk_widget_show(label); + + 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); + gtk_table_attach (GTK_TABLE (pdesc->info_table), help, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 0); + gtk_widget_show (help); + table_row++; + + text = gtk_text_new (NULL, NULL); + gtk_text_set_editable (GTK_TEXT (text), FALSE); + gtk_text_set_word_wrap(GTK_TEXT(text), TRUE); + gtk_widget_set_usize (text, -1, 60); + gtk_table_attach (GTK_TABLE (help), text, 0, 1, 0, 1, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0); + gtk_widget_show (text); + + vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj); + gtk_table_attach (GTK_TABLE (help), vscrollbar, 1, 2, 0, 1, + GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0); + gtk_widget_show (vscrollbar); + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + + gtk_text_freeze (GTK_TEXT (text)); + gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, + selected_proc_help, -1); + gtk_text_thaw (GTK_TEXT (text)); + + table_row++; + } + + /* show the type */ + + label = gtk_label_new("Type :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + + label = gtk_label_new(proc_type_str[selected_proc_type]); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + /* Remove old and replace with new */ + + if(old_table) + gtk_widget_destroy(old_table); + + if(old_align) + gtk_widget_destroy(old_align); + + gtk_container_add (GTK_CONTAINER (pdesc->info_align),pdesc->info_table); + + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (pdesc->descr_scroll), + pdesc->info_align); + + 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) + g_free(selected_proc_help); + 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); + + + return FALSE; +} + +static void +expand_to(PLUGINDESCP pdesc,GtkCTreeNode * parent) +{ + if(parent) + { + expand_to(pdesc,(GTK_CTREE_ROW(parent))->parent); + gtk_ctree_expand(GTK_CTREE(pdesc->ctree),parent); + } +} + +static gint +procedure_clist_select_callback (GtkWidget *widget, + gint row, + gint column, + GdkEventButton * bevent, + gpointer data) +{ + PINFOP pinfo; + GtkCTreeNode * found_node; + PLUGINDESCP pdesc = data; + + g_return_val_if_fail (pdesc != NULL, FALSE); + + pinfo = (PINFOP)gtk_clist_get_row_data (GTK_CLIST (widget), row); + + if(!pinfo) + return FALSE; + + /* Must select the correct one in the ctree structure */ + + found_node = gtk_ctree_find_by_row_data(GTK_CTREE(pdesc->ctree),NULL,pinfo); + + if(found_node) + { + GtkCTreeRow *ctr; + GtkCTreeNode *parent; + int sel_row; + + /* Make sure this is expanded */ + + ctr = GTK_CTREE_ROW(found_node); + + parent = GTK_CTREE_NODE(ctr->parent); + + expand_to(pdesc,parent); + + sel_row = gtk_clist_find_row_from_data(GTK_CLIST(pdesc->ctree),pinfo); + + gtk_widget_hide(pdesc->ctree); + gtk_widget_show(pdesc->ctree); + + gtk_signal_handler_block_by_func(GTK_OBJECT(pdesc->ctree),(GtkSignalFunc)procedure_ctree_select_callback,pdesc); + + + gtk_clist_select_row(GTK_CLIST(pdesc->ctree),sel_row,-1); + gtk_ctree_select(GTK_CTREE(pdesc->ctree),found_node); + + gtk_clist_moveto(GTK_CLIST(pdesc->ctree), + sel_row, + 0, + 0.5,0.5); + + gtk_signal_handler_unblock_by_func(GTK_OBJECT(pdesc->ctree),(GtkSignalFunc)procedure_ctree_select_callback,pdesc); + + pdesc->ctree_row = sel_row; + } + else + { + g_warning("Failed to find node in ctree"); + } + + return procedure_general_select_callback (pdesc,pinfo); +} + +/* This was an attempt to get around a problem in gtk + * where the scroll windows that contain ctree and clist + * refuse to respond to the moveto funcions unless the + * widgets are visible. + * Still did not work 100% even after this. + * Note the scrollbars are in the correct position but the + * widget needs to be redrawn at the correct location. + */ + +static gint +page_select_callback (GtkNotebook *notebook, + GtkNotebookPage *page, + guint page_num, + gpointer data) +{ + PLUGINDESCP pdesc = data; + + if(page_num == 0) + { + gtk_clist_select_row(GTK_CLIST(pdesc->clist),pdesc->clist_row,-1); + gtk_clist_moveto(GTK_CLIST(pdesc->clist), + pdesc->clist_row, + 0, + 0.5,0.5); + } + else + { + gtk_clist_select_row(GTK_CLIST(pdesc->ctree),pdesc->ctree_row,-1); + gtk_clist_moveto(GTK_CLIST(pdesc->ctree), + pdesc->ctree_row, + 0, + 0.5,0.5); + } + return FALSE; +} + +static gint +procedure_ctree_select_callback (GtkWidget *widget, + GtkWidget *row, + gint column, + gpointer data) +{ + PINFOP pinfo; + PLUGINDESCP pdesc; + gboolean is_leaf; + gint sel_row; + + /* row is not a leaf the we have no interest in it */ + + gtk_ctree_get_node_info(GTK_CTREE(widget), + GTK_CTREE_NODE(row), + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &is_leaf, + NULL); + + if(!is_leaf) + { + return FALSE; + } + + pdesc = data; + + pinfo = (PINFOP)gtk_ctree_node_get_row_data (GTK_CTREE(widget),GTK_CTREE_NODE(row)); + + + /* Must set clist to this one */ + /* Block signals */ + + gtk_signal_handler_block_by_func(GTK_OBJECT(pdesc->clist),(GtkSignalFunc)procedure_clist_select_callback,pdesc); + + sel_row = gtk_clist_find_row_from_data(GTK_CLIST(pdesc->clist),pinfo); + gtk_clist_select_row(GTK_CLIST(pdesc->clist),sel_row,-1); + gtk_clist_moveto(GTK_CLIST(pdesc->clist), + sel_row, + 0, + 0.5,0.5); + + gtk_signal_handler_unblock_by_func(GTK_OBJECT(pdesc->clist),(GtkSignalFunc)procedure_clist_select_callback,pdesc); + + pdesc->clist_row = sel_row; + + return procedure_general_select_callback (pdesc,pinfo); +} + +static void +pinfo_free(gpointer p) +{ + PINFOP pinfo = p; + + + g_free(pinfo->menu); + g_free(pinfo->accel); + g_free(pinfo->prog); + g_free(pinfo->types); + g_free(pinfo->realname); + g_free(pinfo); +} + +static GtkCTreeNode* +get_parent(PLUGINDESCP pdesc,GHashTable * ghash,gchar *mpath) +{ + GtkCTreeNode *parent; + GtkCTreeNode *last_parent; + gchar *tmp_ptr; + gchar *str_ptr; + gchar *leaf_ptr; + gchar *labels[3]; + + if(mpath == NULL) + return NULL; /* Parent is root */ + + parent = g_hash_table_lookup(ghash,mpath); + + if(parent) + { + /* found node */ + return (parent); + } + + /* Next one up */ + tmp_ptr = g_strdup(mpath); + + str_ptr = strrchr(tmp_ptr,'/'); + + if(str_ptr == NULL) + { + /* printf("Root node for %s\n",mpath); */ + leaf_ptr = mpath; + tmp_ptr = ""; + last_parent = NULL; + } + else + { + leaf_ptr = g_strdup(str_ptr+1); + + *str_ptr = '\000'; + + last_parent = get_parent(pdesc,ghash,tmp_ptr); + } + + labels[0] = g_strdup(leaf_ptr); + labels[1] = g_strdup(""); + labels[2] = g_strdup(""); + + /* printf("get_parent::creating node %s under %s\n",leaf_ptr,tmp_ptr); */ + + parent = gtk_ctree_insert_node(GTK_CTREE(pdesc->ctree), + last_parent, + NULL, + labels, + 4, + NULL, + NULL, + NULL, + NULL, + FALSE, + FALSE); + + g_hash_table_insert(ghash,mpath,parent); + + return parent; +} + +static void +insert_into_ctree(PLUGINDESCP pdesc,gchar *name, + gchar *xtimestr, + gchar *menu_str, + gchar *types_str, + GHashTable * ghash, + PINFOP pinfo) +{ + gchar *labels[3]; + gchar *str_ptr; + gchar *tmp_ptr; + gchar *leaf_ptr; + GtkCTreeNode *parent = NULL; + GtkCTreeNode *leaf_node = NULL; + + /* Find all nodes */ + /* Last one is the leaf part */ + + tmp_ptr = g_strdup(menu_str); + + str_ptr = strrchr(tmp_ptr,'/'); + + if(str_ptr == NULL) + return; /* No node */ + + leaf_ptr = g_strdup(str_ptr+1); + + *str_ptr = '\000'; + + /* printf("inserting %s...\n",menu_str); */ + + parent = get_parent(pdesc,ghash,tmp_ptr); + + /* Last was a leaf */ + /* printf("found leaf %s parent = %p\n",leaf_ptr,parent); */ + labels[0] = g_strdup(name); + labels[1] = g_strdup(xtimestr); + labels[2] = g_strdup(types_str); + + leaf_node = gtk_ctree_insert_node(GTK_CTREE(pdesc->ctree), + parent, + NULL, + labels, + 4, + NULL, + NULL, + NULL, + NULL, + TRUE, + FALSE); + + gtk_ctree_node_set_row_data(GTK_CTREE(pdesc->ctree),leaf_node,pinfo); + +} + +static void +get_plugin_info(PLUGINDESCP pdesc,gchar *search_text) +{ + GParam *return_vals; + int nreturn_vals; + gint row_count = 0; + gchar **menu_strs; + gchar **accel_strs; + gchar **prog_strs; + gchar **types_strs; + gchar **realname_strs; + gint *time_ints; + + GHashTable* ghash = g_hash_table_new(g_str_hash, g_str_equal); + + if(!search_text) + search_text = ""; + + return_vals = gimp_run_procedure ("gimp_plugins_query", + &nreturn_vals, + PARAM_STRING,search_text, + PARAM_END); + + if (return_vals[0].data.d_status == STATUS_SUCCESS) + { + int loop; + pdesc->num_plugins = return_vals[1].data.d_int32; + 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; + + for (loop = 0; loop < return_vals[1].data.d_int32; loop++) + { + PINFOP pinfo; + gchar *labels[4]; + 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) + { + x = localtime(&tx); + ret = strftime(xtimestr,sizeof(xtimestr), "%c",x); + xtimestr[ret] = 0; + } + 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]); + + labels[0] = g_strdup(name); + labels[1] = g_strdup(xtimestr); + labels[2] = g_strdup(menu_strs[loop]); + labels[3] = g_strdup(types_strs[loop]); + + gtk_clist_insert (GTK_CLIST (GTK_CLIST(pdesc->clist)), row_count, + labels); + + gtk_clist_set_row_data_full(GTK_CLIST(pdesc->clist), row_count, + pinfo,pinfo_free); + + row_count++; + + /* Now do the tree view.... */ + insert_into_ctree(pdesc, + name, + xtimestr, + menu_strs[loop], + types_strs[loop], + ghash, + pinfo); + } + } + + gimp_destroy_params (return_vals, nreturn_vals); +} + +static void +dialog_search_callback (GtkWidget *widget, + gpointer data) +{ + PLUGINDESCP pdesc = data; + gchar *search_text = NULL; + + if(widget != NULL) + { + /* The result of a button press... read entry data */ + search_text = gtk_entry_get_text(GTK_ENTRY(plugindesc->search_entry)); + } + + gtk_clist_freeze(GTK_CLIST(pdesc->ctree)); + gtk_clist_clear(GTK_CLIST(pdesc->ctree)); + gtk_clist_freeze(GTK_CLIST(pdesc->clist)); + gtk_clist_clear(GTK_CLIST(pdesc->clist)); + + get_plugin_info(pdesc,search_text); + + gtk_clist_columns_autosize(GTK_CLIST(plugindesc->clist)); + + gtk_clist_sort(GTK_CLIST(pdesc->clist)); + gtk_clist_thaw(GTK_CLIST(pdesc->clist)); + gtk_ctree_sort_recursive(GTK_CTREE(pdesc->ctree),NULL); + gtk_clist_thaw(GTK_CLIST(pdesc->ctree)); +} + +static gint +date_sort(GtkCList *clist, + gconstpointer ptr1, + gconstpointer ptr2) +{ + GtkCListRow *row1 = (GtkCListRow *) ptr1; + GtkCListRow *row2 = (GtkCListRow *) ptr2; + + /* Get the data for the row */ + PINFOP row1_pinfo = row1->data; + PINFOP row2_pinfo = row2->data; + + /* Want to sort on the date field */ + + if(row2_pinfo->instime < row1_pinfo->instime) + { + return(-1); + } + + if(row2_pinfo->instime > row1_pinfo->instime) + { + return(1); + } + + return(0); +} + +static void +clist_click_column (GtkCList *clist, gint column, gpointer data) +{ + if (column == 1) + { + gtk_clist_set_compare_func(clist,date_sort); + } + else + { + gtk_clist_set_compare_func(clist,NULL); /* Set back to default */ + } + + if (column == clist->sort_column) + { + if (clist->sort_type == GTK_SORT_ASCENDING) + clist->sort_type = GTK_SORT_DESCENDING; + else + clist->sort_type = GTK_SORT_ASCENDING; + } + else + gtk_clist_set_sort_column (clist, column); + + gtk_clist_sort (clist); +} + + +static GtkWidget * +gimp_plugin_desc() +{ + GtkWidget *button; + GtkWidget *hbox,*searchhbox,*vbox; + GtkWidget *label,*notebook,*swindow; + gchar **argv; + gint argc; + gchar *clabels[4]; + + argc = 1; + argv = g_new (gchar *, 1); + argv[0] = g_strdup ("plugin_desc"); + + gtk_init (&argc, &argv); + gtk_rc_parse (gimp_gtkrc ()); + + plugindesc = g_new0(PLUGINDESC,1); + + /* the dialog box */ + + plugindesc->dlg = gtk_dialog_new(); + plugindesc->details_showing = FALSE; + + gtk_window_set_title (GTK_WINDOW (plugindesc->dlg), "Plugin Descriptions"); + gtk_window_position (GTK_WINDOW (plugindesc->dlg), GTK_WIN_POS_MOUSE); + gtk_signal_connect (GTK_OBJECT (plugindesc->dlg), "destroy", + (GtkSignalFunc) dialog_close_callback, + plugindesc); + gtk_window_set_policy(GTK_WINDOW (plugindesc->dlg),TRUE,TRUE,TRUE); + + /* hbox : left=notebook ; right=description */ + + hbox = gtk_hpaned_new(); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (plugindesc->dlg)->vbox), + hbox, TRUE, TRUE, 0); + gtk_widget_show (hbox); + + + /* left = vbox : the list and the search entry */ + + vbox = gtk_vbox_new( FALSE, 0 ); + gtk_container_border_width (GTK_CONTAINER (vbox), 3); + gtk_paned_add1 (GTK_PANED (hbox),vbox); + gtk_widget_show(vbox); + + /* left = notebook */ + + notebook = gtk_notebook_new(); + gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0); + + /* list : list in a scrolled_win */ + + clabels[0] = g_strdup("Name"); + clabels[1] = g_strdup("Ins Date"); + clabels[2] = g_strdup("Menu Path"); + clabels[3] = g_strdup("Image Types"); + plugindesc->clist = gtk_clist_new_with_titles(4,clabels); + + gtk_signal_connect (GTK_OBJECT (plugindesc->clist), "click_column", + (GtkSignalFunc) clist_click_column, NULL); + gtk_clist_column_titles_show(GTK_CLIST(plugindesc->clist)); + swindow = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_clist_set_selection_mode (GTK_CLIST (plugindesc->clist), + GTK_SELECTION_BROWSE); + + gtk_widget_set_usize(plugindesc->clist, DBL_LIST_WIDTH, DBL_HEIGHT); + gtk_signal_connect (GTK_OBJECT (plugindesc->clist), "select_row", + (GtkSignalFunc) procedure_clist_select_callback, + plugindesc); + + label = gtk_label_new("List view"); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook),swindow,label); + gtk_container_add (GTK_CONTAINER (swindow), plugindesc->clist); + gtk_widget_show(plugindesc->clist); + gtk_widget_show(swindow); + + /* notebook->ctree */ + clabels[0] = g_strdup("Menu Path/Name"); + clabels[1] = g_strdup("Ins Date"); + clabels[2] = g_strdup("Image Types"); + plugindesc->ctree = gtk_ctree_new_with_titles(3,0,clabels); + plugindesc->ctree_scrolled_win = + swindow = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_widget_set_usize(plugindesc->ctree, DBL_LIST_WIDTH, DBL_HEIGHT); + gtk_signal_connect (GTK_OBJECT (plugindesc->ctree), "tree_select_row", + (GtkSignalFunc) procedure_ctree_select_callback, + plugindesc); + label = gtk_label_new("Tree view"); + gtk_clist_set_column_auto_resize (GTK_CLIST (plugindesc->ctree), 0, TRUE); + gtk_clist_set_column_auto_resize (GTK_CLIST (plugindesc->ctree), 1, TRUE); + gtk_clist_set_column_auto_resize (GTK_CLIST (plugindesc->ctree), 2, TRUE); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook),swindow,label); + gtk_container_add (GTK_CONTAINER (swindow), plugindesc->ctree); + gtk_widget_show(plugindesc->ctree); + gtk_widget_show(swindow); + + gtk_signal_connect_after (GTK_OBJECT (notebook), "switch_page", + (GtkSignalFunc) page_select_callback, + plugindesc); + + gtk_widget_show(notebook); + + /* search entry & details button */ + + searchhbox = gtk_hbox_new(FALSE,0); + gtk_box_pack_start (GTK_BOX (vbox), + searchhbox, FALSE, TRUE, 0); + gtk_widget_show(searchhbox); + + label = gtk_label_new("Search :"); + gtk_misc_set_alignment( GTK_MISC(label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (searchhbox), + label, TRUE, TRUE, 0); + gtk_widget_show(label); + + plugindesc->search_entry = gtk_entry_new(); + gtk_box_pack_start (GTK_BOX (searchhbox), + plugindesc->search_entry, TRUE, TRUE, 0); + gtk_widget_show(plugindesc->search_entry); + + button = gtk_button_new_with_label ("Details >>>"); + gtk_widget_show(button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) details_callback, plugindesc); + gtk_box_pack_start (GTK_BOX (searchhbox), + button, TRUE, TRUE, 0); + + /* right = description */ + + plugindesc->descr_scroll = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (plugindesc->descr_scroll), + GTK_POLICY_ALWAYS, + GTK_POLICY_ALWAYS + ); + gtk_paned_add2 (GTK_PANED (hbox), plugindesc->descr_scroll); + gtk_widget_set_usize (plugindesc->descr_scroll, DBL_WIDTH - DBL_LIST_WIDTH, 0); + + /* buttons in dlg->action_area */ + + gtk_container_border_width (GTK_CONTAINER (GTK_DIALOG(plugindesc->dlg)->action_area), 0); + + plugindesc->name_button = gtk_button_new_with_label ("Search by name"); + GTK_WIDGET_SET_FLAGS (plugindesc->name_button, GTK_CAN_DEFAULT); + gtk_signal_connect (GTK_OBJECT (plugindesc->name_button), "clicked", + (GtkSignalFunc) dialog_search_callback, plugindesc); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (plugindesc->dlg)->action_area), + plugindesc->name_button , TRUE, TRUE, 0); + gtk_widget_show(plugindesc->name_button); + + + button = gtk_button_new_with_label ("Close"); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) dialog_close_callback, plugindesc); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (plugindesc->dlg)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + + + /* now build the list */ + dialog_search_callback( NULL, (gpointer)plugindesc); + + gtk_widget_show (plugindesc->clist); + gtk_widget_show (plugindesc->dlg); + + return plugindesc->dlg; +} + diff --git a/plug-ins/common/plugindetails.c b/plug-ins/common/plugindetails.c new file mode 100644 index 0000000000..fddbe758fc --- /dev/null +++ b/plug-ins/common/plugindetails.c @@ -0,0 +1,1097 @@ +/* + * 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 + * + * Note some portions of th UI comes from the dbbrowser plugin. + * 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. + */ + +#include +#include +#include +#include +#include +#include "gtk/gtk.h" +#include "libgimp/gimp.h" + +#define DBL_LIST_WIDTH 250 +#define DBL_WIDTH DBL_LIST_WIDTH+450 +#define DBL_HEIGHT 200 + +static char *proc_type_str[] = +{ + "Internal GIMP procedure", + "GIMP Plug-In", + "GIMP Extension", + "Temporary Procedure" +}; + + +/* Declare some local functions. + */ +static void query (void); +static void run (char *name, + int nparams, + GParam *param, + int *nreturn_vals, + GParam **return_vals); + +static GtkWidget * gimp_plugin_desc(); +static gint procedure_clist_select_callback (GtkWidget *widget, + gint row, + gint column, + GdkEventButton * bevent, + gpointer data); +static gint procedure_ctree_select_callback (GtkWidget *widget, + GtkWidget *row, + gint column, + gpointer data); + +GPlugInInfo PLUG_IN_INFO = +{ + NULL, /* init_proc */ + NULL, /* quit_proc */ + query, /* query_proc */ + run, /* run_proc */ +}; + + +MAIN () + +static void +query () +{ + static GParamDef args[] = + { + { PARAM_INT32, "run_mode", "Interactive, [non-interactive]" } + }; + + static int nargs = sizeof (args) / sizeof (args[0]); + + gimp_install_procedure ("plug_in_details", + "Displays plugin details", + "Helps browse the plugin menus system. You can 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", + "Andy Thomas", + "Andy Thomas", + "1999", + "/Xtns/Plugin Details", + "", + PROC_EXTENSION, + nargs, 0, + args, NULL); +} + +static void +run (char *name, + int nparams, + GParam *param, + int *nreturn_vals, + GParam **return_vals) +{ + static GParam values[2]; + GRunModeType run_mode; + GtkWidget * plugin_dialog; + + run_mode = param[0].data.d_int32; + + *nreturn_vals = 1; + *return_vals = values; + values[0].type = PARAM_STATUS; + values[0].data.d_status = STATUS_CALLING_ERROR; + + if (strcmp (name, "plug_in_details") == 0) + { + *nreturn_vals = 1; + + values[0].data.d_status = STATUS_SUCCESS; + + plugin_dialog = gimp_plugin_desc(); + gtk_widget_show(plugin_dialog); + gtk_main (); + gdk_flush (); + } +} + + +typedef struct +{ + GtkWidget * dlg; + GtkWidget * clist; + GtkWidget * ctree; + GtkWidget * search_entry; + GtkWidget * descr_scroll; + GtkWidget * name_button; + GtkWidget * blurb_button; + GtkWidget * scrolled_win; + GtkWidget * ctree_scrolled_win; + GtkWidget * info_table; + GtkWidget * info_align; + gint num_plugins; + gint ctree_row; + gint clist_row; + gboolean details_showing; +} PLUGINDESC,*PLUGINDESCP; + +PLUGINDESCP plugindesc = NULL; + +typedef struct +{ + gchar *menu; + gchar *accel; + gchar *prog; + gchar *types; + gchar *realname; + gint instime; +} PINFO, *PINFOP; + +static void +dialog_close_callback (GtkWidget *widget, + gpointer data) + /* end of the dialog */ +{ + PLUGINDESCP pdesc = data; + gtk_widget_destroy(pdesc->dlg); + gtk_main_quit (); +} + +static void +details_callback (GtkWidget *widget, + gpointer data) +{ + /* Show or hide the details window */ + PLUGINDESCP pdesc = data; + GtkLabel *lab = GTK_LABEL(GTK_BIN (widget)->child); + + if(pdesc->details_showing == FALSE) + { + gtk_label_set_text(lab,"Details <<<"); + gtk_widget_show (pdesc->descr_scroll); + pdesc->details_showing = TRUE; + } + else + { + gtk_label_set_text(lab,"Details >>>"); + gtk_widget_hide (pdesc->descr_scroll); + pdesc->details_showing = FALSE; + } +} + +static gchar * +format_menu_path(gchar *s) +{ + gchar ** str_array; + gchar *newstr = NULL; + + if(!s) + return s; + + str_array = g_strsplit(s,"/",0); + + newstr = g_strjoinv("->",str_array); + + g_strfreev(str_array); + + return newstr; +} + +static gint +procedure_general_select_callback (PLUGINDESCP pdesc, + PINFOP pinfo) +{ + gchar *selected_proc_blurb; + gchar *selected_proc_help; + gchar *selected_proc_author; + gchar *selected_proc_copyright; + gchar *selected_proc_date; + gint selected_proc_type; + gint selected_nparams; + gint selected_nreturn_vals; + GParamDef *selected_params; + GParamDef *selected_return_vals; + GtkWidget *label; + GtkWidget *help; + GtkWidget *text; + GtkWidget *vscrollbar; + GtkWidget *old_table; + GtkWidget *old_align; + gint table_row = 0; + + g_return_val_if_fail (pdesc != NULL, FALSE); + + g_return_val_if_fail (pinfo != NULL, FALSE); + + selected_proc_blurb = NULL; + selected_proc_help = NULL; + selected_proc_author = NULL; + selected_proc_copyright = NULL; + selected_proc_date = NULL; + selected_proc_type = 0; + selected_nparams = 0; + selected_nreturn_vals = 0; + selected_params = NULL; + selected_return_vals = NULL; + + gimp_query_procedure (pinfo->realname, + &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); + + old_table = pdesc->info_table; + old_align = pdesc->info_align; + + pdesc->info_table = gtk_table_new(10 ,5 , FALSE); + pdesc->info_align = gtk_alignment_new (0.5, 0.5, 0, 0); + + gtk_table_set_col_spacings( GTK_TABLE(pdesc->info_table), 3); + + /* Number of plugins */ + + label = gtk_label_new(g_strdup_printf(" Number of plugin interfaces :%d",pdesc->num_plugins)); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + + /* menu path */ + + label = gtk_label_new("Menu path :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 0); + gtk_widget_show(label); + + label = gtk_label_new(format_menu_path(pinfo->menu)); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + /* show the name */ + + label = gtk_label_new("Name :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + + label = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(label),pinfo->realname); + gtk_entry_set_editable(GTK_ENTRY(label), FALSE); + gtk_table_attach (GTK_TABLE(pdesc->info_table), label, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + /* show the description */ + + label = gtk_label_new("Blurb :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 0); + gtk_widget_show(label); + + label = gtk_label_new(selected_proc_blurb); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + /* show the help */ + if ((selected_proc_help) && (strlen(selected_proc_help) > 1)) + { + label = gtk_label_new("Help :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, + GTK_FILL, GTK_FILL, 3, 0); + gtk_widget_show(label); + + 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); + gtk_table_attach (GTK_TABLE (pdesc->info_table), help, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 0); + gtk_widget_show (help); + table_row++; + + text = gtk_text_new (NULL, NULL); + gtk_text_set_editable (GTK_TEXT (text), FALSE); + gtk_text_set_word_wrap(GTK_TEXT(text), TRUE); + gtk_widget_set_usize (text, -1, 60); + gtk_table_attach (GTK_TABLE (help), text, 0, 1, 0, 1, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0); + gtk_widget_show (text); + + vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj); + gtk_table_attach (GTK_TABLE (help), vscrollbar, 1, 2, 0, 1, + GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0); + gtk_widget_show (vscrollbar); + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + + gtk_text_freeze (GTK_TEXT (text)); + gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, + selected_proc_help, -1); + gtk_text_thaw (GTK_TEXT (text)); + + table_row++; + } + + /* show the type */ + + label = gtk_label_new("Type :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + + label = gtk_label_new(proc_type_str[selected_proc_type]); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + /* Remove old and replace with new */ + + if(old_table) + gtk_widget_destroy(old_table); + + if(old_align) + gtk_widget_destroy(old_align); + + gtk_container_add (GTK_CONTAINER (pdesc->info_align),pdesc->info_table); + + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (pdesc->descr_scroll), + pdesc->info_align); + + 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) + g_free(selected_proc_help); + 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); + + + return FALSE; +} + +static void +expand_to(PLUGINDESCP pdesc,GtkCTreeNode * parent) +{ + if(parent) + { + expand_to(pdesc,(GTK_CTREE_ROW(parent))->parent); + gtk_ctree_expand(GTK_CTREE(pdesc->ctree),parent); + } +} + +static gint +procedure_clist_select_callback (GtkWidget *widget, + gint row, + gint column, + GdkEventButton * bevent, + gpointer data) +{ + PINFOP pinfo; + GtkCTreeNode * found_node; + PLUGINDESCP pdesc = data; + + g_return_val_if_fail (pdesc != NULL, FALSE); + + pinfo = (PINFOP)gtk_clist_get_row_data (GTK_CLIST (widget), row); + + if(!pinfo) + return FALSE; + + /* Must select the correct one in the ctree structure */ + + found_node = gtk_ctree_find_by_row_data(GTK_CTREE(pdesc->ctree),NULL,pinfo); + + if(found_node) + { + GtkCTreeRow *ctr; + GtkCTreeNode *parent; + int sel_row; + + /* Make sure this is expanded */ + + ctr = GTK_CTREE_ROW(found_node); + + parent = GTK_CTREE_NODE(ctr->parent); + + expand_to(pdesc,parent); + + sel_row = gtk_clist_find_row_from_data(GTK_CLIST(pdesc->ctree),pinfo); + + gtk_widget_hide(pdesc->ctree); + gtk_widget_show(pdesc->ctree); + + gtk_signal_handler_block_by_func(GTK_OBJECT(pdesc->ctree),(GtkSignalFunc)procedure_ctree_select_callback,pdesc); + + + gtk_clist_select_row(GTK_CLIST(pdesc->ctree),sel_row,-1); + gtk_ctree_select(GTK_CTREE(pdesc->ctree),found_node); + + gtk_clist_moveto(GTK_CLIST(pdesc->ctree), + sel_row, + 0, + 0.5,0.5); + + gtk_signal_handler_unblock_by_func(GTK_OBJECT(pdesc->ctree),(GtkSignalFunc)procedure_ctree_select_callback,pdesc); + + pdesc->ctree_row = sel_row; + } + else + { + g_warning("Failed to find node in ctree"); + } + + return procedure_general_select_callback (pdesc,pinfo); +} + +/* This was an attempt to get around a problem in gtk + * where the scroll windows that contain ctree and clist + * refuse to respond to the moveto funcions unless the + * widgets are visible. + * Still did not work 100% even after this. + * Note the scrollbars are in the correct position but the + * widget needs to be redrawn at the correct location. + */ + +static gint +page_select_callback (GtkNotebook *notebook, + GtkNotebookPage *page, + guint page_num, + gpointer data) +{ + PLUGINDESCP pdesc = data; + + if(page_num == 0) + { + gtk_clist_select_row(GTK_CLIST(pdesc->clist),pdesc->clist_row,-1); + gtk_clist_moveto(GTK_CLIST(pdesc->clist), + pdesc->clist_row, + 0, + 0.5,0.5); + } + else + { + gtk_clist_select_row(GTK_CLIST(pdesc->ctree),pdesc->ctree_row,-1); + gtk_clist_moveto(GTK_CLIST(pdesc->ctree), + pdesc->ctree_row, + 0, + 0.5,0.5); + } + return FALSE; +} + +static gint +procedure_ctree_select_callback (GtkWidget *widget, + GtkWidget *row, + gint column, + gpointer data) +{ + PINFOP pinfo; + PLUGINDESCP pdesc; + gboolean is_leaf; + gint sel_row; + + /* row is not a leaf the we have no interest in it */ + + gtk_ctree_get_node_info(GTK_CTREE(widget), + GTK_CTREE_NODE(row), + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &is_leaf, + NULL); + + if(!is_leaf) + { + return FALSE; + } + + pdesc = data; + + pinfo = (PINFOP)gtk_ctree_node_get_row_data (GTK_CTREE(widget),GTK_CTREE_NODE(row)); + + + /* Must set clist to this one */ + /* Block signals */ + + gtk_signal_handler_block_by_func(GTK_OBJECT(pdesc->clist),(GtkSignalFunc)procedure_clist_select_callback,pdesc); + + sel_row = gtk_clist_find_row_from_data(GTK_CLIST(pdesc->clist),pinfo); + gtk_clist_select_row(GTK_CLIST(pdesc->clist),sel_row,-1); + gtk_clist_moveto(GTK_CLIST(pdesc->clist), + sel_row, + 0, + 0.5,0.5); + + gtk_signal_handler_unblock_by_func(GTK_OBJECT(pdesc->clist),(GtkSignalFunc)procedure_clist_select_callback,pdesc); + + pdesc->clist_row = sel_row; + + return procedure_general_select_callback (pdesc,pinfo); +} + +static void +pinfo_free(gpointer p) +{ + PINFOP pinfo = p; + + + g_free(pinfo->menu); + g_free(pinfo->accel); + g_free(pinfo->prog); + g_free(pinfo->types); + g_free(pinfo->realname); + g_free(pinfo); +} + +static GtkCTreeNode* +get_parent(PLUGINDESCP pdesc,GHashTable * ghash,gchar *mpath) +{ + GtkCTreeNode *parent; + GtkCTreeNode *last_parent; + gchar *tmp_ptr; + gchar *str_ptr; + gchar *leaf_ptr; + gchar *labels[3]; + + if(mpath == NULL) + return NULL; /* Parent is root */ + + parent = g_hash_table_lookup(ghash,mpath); + + if(parent) + { + /* found node */ + return (parent); + } + + /* Next one up */ + tmp_ptr = g_strdup(mpath); + + str_ptr = strrchr(tmp_ptr,'/'); + + if(str_ptr == NULL) + { + /* printf("Root node for %s\n",mpath); */ + leaf_ptr = mpath; + tmp_ptr = ""; + last_parent = NULL; + } + else + { + leaf_ptr = g_strdup(str_ptr+1); + + *str_ptr = '\000'; + + last_parent = get_parent(pdesc,ghash,tmp_ptr); + } + + labels[0] = g_strdup(leaf_ptr); + labels[1] = g_strdup(""); + labels[2] = g_strdup(""); + + /* printf("get_parent::creating node %s under %s\n",leaf_ptr,tmp_ptr); */ + + parent = gtk_ctree_insert_node(GTK_CTREE(pdesc->ctree), + last_parent, + NULL, + labels, + 4, + NULL, + NULL, + NULL, + NULL, + FALSE, + FALSE); + + g_hash_table_insert(ghash,mpath,parent); + + return parent; +} + +static void +insert_into_ctree(PLUGINDESCP pdesc,gchar *name, + gchar *xtimestr, + gchar *menu_str, + gchar *types_str, + GHashTable * ghash, + PINFOP pinfo) +{ + gchar *labels[3]; + gchar *str_ptr; + gchar *tmp_ptr; + gchar *leaf_ptr; + GtkCTreeNode *parent = NULL; + GtkCTreeNode *leaf_node = NULL; + + /* Find all nodes */ + /* Last one is the leaf part */ + + tmp_ptr = g_strdup(menu_str); + + str_ptr = strrchr(tmp_ptr,'/'); + + if(str_ptr == NULL) + return; /* No node */ + + leaf_ptr = g_strdup(str_ptr+1); + + *str_ptr = '\000'; + + /* printf("inserting %s...\n",menu_str); */ + + parent = get_parent(pdesc,ghash,tmp_ptr); + + /* Last was a leaf */ + /* printf("found leaf %s parent = %p\n",leaf_ptr,parent); */ + labels[0] = g_strdup(name); + labels[1] = g_strdup(xtimestr); + labels[2] = g_strdup(types_str); + + leaf_node = gtk_ctree_insert_node(GTK_CTREE(pdesc->ctree), + parent, + NULL, + labels, + 4, + NULL, + NULL, + NULL, + NULL, + TRUE, + FALSE); + + gtk_ctree_node_set_row_data(GTK_CTREE(pdesc->ctree),leaf_node,pinfo); + +} + +static void +get_plugin_info(PLUGINDESCP pdesc,gchar *search_text) +{ + GParam *return_vals; + int nreturn_vals; + gint row_count = 0; + gchar **menu_strs; + gchar **accel_strs; + gchar **prog_strs; + gchar **types_strs; + gchar **realname_strs; + gint *time_ints; + + GHashTable* ghash = g_hash_table_new(g_str_hash, g_str_equal); + + if(!search_text) + search_text = ""; + + return_vals = gimp_run_procedure ("gimp_plugins_query", + &nreturn_vals, + PARAM_STRING,search_text, + PARAM_END); + + if (return_vals[0].data.d_status == STATUS_SUCCESS) + { + int loop; + pdesc->num_plugins = return_vals[1].data.d_int32; + 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; + + for (loop = 0; loop < return_vals[1].data.d_int32; loop++) + { + PINFOP pinfo; + gchar *labels[4]; + 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) + { + x = localtime(&tx); + ret = strftime(xtimestr,sizeof(xtimestr), "%c",x); + xtimestr[ret] = 0; + } + 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]); + + labels[0] = g_strdup(name); + labels[1] = g_strdup(xtimestr); + labels[2] = g_strdup(menu_strs[loop]); + labels[3] = g_strdup(types_strs[loop]); + + gtk_clist_insert (GTK_CLIST (GTK_CLIST(pdesc->clist)), row_count, + labels); + + gtk_clist_set_row_data_full(GTK_CLIST(pdesc->clist), row_count, + pinfo,pinfo_free); + + row_count++; + + /* Now do the tree view.... */ + insert_into_ctree(pdesc, + name, + xtimestr, + menu_strs[loop], + types_strs[loop], + ghash, + pinfo); + } + } + + gimp_destroy_params (return_vals, nreturn_vals); +} + +static void +dialog_search_callback (GtkWidget *widget, + gpointer data) +{ + PLUGINDESCP pdesc = data; + gchar *search_text = NULL; + + if(widget != NULL) + { + /* The result of a button press... read entry data */ + search_text = gtk_entry_get_text(GTK_ENTRY(plugindesc->search_entry)); + } + + gtk_clist_freeze(GTK_CLIST(pdesc->ctree)); + gtk_clist_clear(GTK_CLIST(pdesc->ctree)); + gtk_clist_freeze(GTK_CLIST(pdesc->clist)); + gtk_clist_clear(GTK_CLIST(pdesc->clist)); + + get_plugin_info(pdesc,search_text); + + gtk_clist_columns_autosize(GTK_CLIST(plugindesc->clist)); + + gtk_clist_sort(GTK_CLIST(pdesc->clist)); + gtk_clist_thaw(GTK_CLIST(pdesc->clist)); + gtk_ctree_sort_recursive(GTK_CTREE(pdesc->ctree),NULL); + gtk_clist_thaw(GTK_CLIST(pdesc->ctree)); +} + +static gint +date_sort(GtkCList *clist, + gconstpointer ptr1, + gconstpointer ptr2) +{ + GtkCListRow *row1 = (GtkCListRow *) ptr1; + GtkCListRow *row2 = (GtkCListRow *) ptr2; + + /* Get the data for the row */ + PINFOP row1_pinfo = row1->data; + PINFOP row2_pinfo = row2->data; + + /* Want to sort on the date field */ + + if(row2_pinfo->instime < row1_pinfo->instime) + { + return(-1); + } + + if(row2_pinfo->instime > row1_pinfo->instime) + { + return(1); + } + + return(0); +} + +static void +clist_click_column (GtkCList *clist, gint column, gpointer data) +{ + if (column == 1) + { + gtk_clist_set_compare_func(clist,date_sort); + } + else + { + gtk_clist_set_compare_func(clist,NULL); /* Set back to default */ + } + + if (column == clist->sort_column) + { + if (clist->sort_type == GTK_SORT_ASCENDING) + clist->sort_type = GTK_SORT_DESCENDING; + else + clist->sort_type = GTK_SORT_ASCENDING; + } + else + gtk_clist_set_sort_column (clist, column); + + gtk_clist_sort (clist); +} + + +static GtkWidget * +gimp_plugin_desc() +{ + GtkWidget *button; + GtkWidget *hbox,*searchhbox,*vbox; + GtkWidget *label,*notebook,*swindow; + gchar **argv; + gint argc; + gchar *clabels[4]; + + argc = 1; + argv = g_new (gchar *, 1); + argv[0] = g_strdup ("plugin_desc"); + + gtk_init (&argc, &argv); + gtk_rc_parse (gimp_gtkrc ()); + + plugindesc = g_new0(PLUGINDESC,1); + + /* the dialog box */ + + plugindesc->dlg = gtk_dialog_new(); + plugindesc->details_showing = FALSE; + + gtk_window_set_title (GTK_WINDOW (plugindesc->dlg), "Plugin Descriptions"); + gtk_window_position (GTK_WINDOW (plugindesc->dlg), GTK_WIN_POS_MOUSE); + gtk_signal_connect (GTK_OBJECT (plugindesc->dlg), "destroy", + (GtkSignalFunc) dialog_close_callback, + plugindesc); + gtk_window_set_policy(GTK_WINDOW (plugindesc->dlg),TRUE,TRUE,TRUE); + + /* hbox : left=notebook ; right=description */ + + hbox = gtk_hpaned_new(); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (plugindesc->dlg)->vbox), + hbox, TRUE, TRUE, 0); + gtk_widget_show (hbox); + + + /* left = vbox : the list and the search entry */ + + vbox = gtk_vbox_new( FALSE, 0 ); + gtk_container_border_width (GTK_CONTAINER (vbox), 3); + gtk_paned_add1 (GTK_PANED (hbox),vbox); + gtk_widget_show(vbox); + + /* left = notebook */ + + notebook = gtk_notebook_new(); + gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0); + + /* list : list in a scrolled_win */ + + clabels[0] = g_strdup("Name"); + clabels[1] = g_strdup("Ins Date"); + clabels[2] = g_strdup("Menu Path"); + clabels[3] = g_strdup("Image Types"); + plugindesc->clist = gtk_clist_new_with_titles(4,clabels); + + gtk_signal_connect (GTK_OBJECT (plugindesc->clist), "click_column", + (GtkSignalFunc) clist_click_column, NULL); + gtk_clist_column_titles_show(GTK_CLIST(plugindesc->clist)); + swindow = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_clist_set_selection_mode (GTK_CLIST (plugindesc->clist), + GTK_SELECTION_BROWSE); + + gtk_widget_set_usize(plugindesc->clist, DBL_LIST_WIDTH, DBL_HEIGHT); + gtk_signal_connect (GTK_OBJECT (plugindesc->clist), "select_row", + (GtkSignalFunc) procedure_clist_select_callback, + plugindesc); + + label = gtk_label_new("List view"); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook),swindow,label); + gtk_container_add (GTK_CONTAINER (swindow), plugindesc->clist); + gtk_widget_show(plugindesc->clist); + gtk_widget_show(swindow); + + /* notebook->ctree */ + clabels[0] = g_strdup("Menu Path/Name"); + clabels[1] = g_strdup("Ins Date"); + clabels[2] = g_strdup("Image Types"); + plugindesc->ctree = gtk_ctree_new_with_titles(3,0,clabels); + plugindesc->ctree_scrolled_win = + swindow = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_widget_set_usize(plugindesc->ctree, DBL_LIST_WIDTH, DBL_HEIGHT); + gtk_signal_connect (GTK_OBJECT (plugindesc->ctree), "tree_select_row", + (GtkSignalFunc) procedure_ctree_select_callback, + plugindesc); + label = gtk_label_new("Tree view"); + gtk_clist_set_column_auto_resize (GTK_CLIST (plugindesc->ctree), 0, TRUE); + gtk_clist_set_column_auto_resize (GTK_CLIST (plugindesc->ctree), 1, TRUE); + gtk_clist_set_column_auto_resize (GTK_CLIST (plugindesc->ctree), 2, TRUE); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook),swindow,label); + gtk_container_add (GTK_CONTAINER (swindow), plugindesc->ctree); + gtk_widget_show(plugindesc->ctree); + gtk_widget_show(swindow); + + gtk_signal_connect_after (GTK_OBJECT (notebook), "switch_page", + (GtkSignalFunc) page_select_callback, + plugindesc); + + gtk_widget_show(notebook); + + /* search entry & details button */ + + searchhbox = gtk_hbox_new(FALSE,0); + gtk_box_pack_start (GTK_BOX (vbox), + searchhbox, FALSE, TRUE, 0); + gtk_widget_show(searchhbox); + + label = gtk_label_new("Search :"); + gtk_misc_set_alignment( GTK_MISC(label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (searchhbox), + label, TRUE, TRUE, 0); + gtk_widget_show(label); + + plugindesc->search_entry = gtk_entry_new(); + gtk_box_pack_start (GTK_BOX (searchhbox), + plugindesc->search_entry, TRUE, TRUE, 0); + gtk_widget_show(plugindesc->search_entry); + + button = gtk_button_new_with_label ("Details >>>"); + gtk_widget_show(button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) details_callback, plugindesc); + gtk_box_pack_start (GTK_BOX (searchhbox), + button, TRUE, TRUE, 0); + + /* right = description */ + + plugindesc->descr_scroll = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (plugindesc->descr_scroll), + GTK_POLICY_ALWAYS, + GTK_POLICY_ALWAYS + ); + gtk_paned_add2 (GTK_PANED (hbox), plugindesc->descr_scroll); + gtk_widget_set_usize (plugindesc->descr_scroll, DBL_WIDTH - DBL_LIST_WIDTH, 0); + + /* buttons in dlg->action_area */ + + gtk_container_border_width (GTK_CONTAINER (GTK_DIALOG(plugindesc->dlg)->action_area), 0); + + plugindesc->name_button = gtk_button_new_with_label ("Search by name"); + GTK_WIDGET_SET_FLAGS (plugindesc->name_button, GTK_CAN_DEFAULT); + gtk_signal_connect (GTK_OBJECT (plugindesc->name_button), "clicked", + (GtkSignalFunc) dialog_search_callback, plugindesc); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (plugindesc->dlg)->action_area), + plugindesc->name_button , TRUE, TRUE, 0); + gtk_widget_show(plugindesc->name_button); + + + button = gtk_button_new_with_label ("Close"); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) dialog_close_callback, plugindesc); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (plugindesc->dlg)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + + + /* now build the list */ + dialog_search_callback( NULL, (gpointer)plugindesc); + + gtk_widget_show (plugindesc->clist); + gtk_widget_show (plugindesc->dlg); + + return plugindesc->dlg; +} + diff --git a/plug-ins/dbbrowser/plugin-browser.c b/plug-ins/dbbrowser/plugin-browser.c new file mode 100644 index 0000000000..fddbe758fc --- /dev/null +++ b/plug-ins/dbbrowser/plugin-browser.c @@ -0,0 +1,1097 @@ +/* + * 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 + * + * Note some portions of th UI comes from the dbbrowser plugin. + * 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. + */ + +#include +#include +#include +#include +#include +#include "gtk/gtk.h" +#include "libgimp/gimp.h" + +#define DBL_LIST_WIDTH 250 +#define DBL_WIDTH DBL_LIST_WIDTH+450 +#define DBL_HEIGHT 200 + +static char *proc_type_str[] = +{ + "Internal GIMP procedure", + "GIMP Plug-In", + "GIMP Extension", + "Temporary Procedure" +}; + + +/* Declare some local functions. + */ +static void query (void); +static void run (char *name, + int nparams, + GParam *param, + int *nreturn_vals, + GParam **return_vals); + +static GtkWidget * gimp_plugin_desc(); +static gint procedure_clist_select_callback (GtkWidget *widget, + gint row, + gint column, + GdkEventButton * bevent, + gpointer data); +static gint procedure_ctree_select_callback (GtkWidget *widget, + GtkWidget *row, + gint column, + gpointer data); + +GPlugInInfo PLUG_IN_INFO = +{ + NULL, /* init_proc */ + NULL, /* quit_proc */ + query, /* query_proc */ + run, /* run_proc */ +}; + + +MAIN () + +static void +query () +{ + static GParamDef args[] = + { + { PARAM_INT32, "run_mode", "Interactive, [non-interactive]" } + }; + + static int nargs = sizeof (args) / sizeof (args[0]); + + gimp_install_procedure ("plug_in_details", + "Displays plugin details", + "Helps browse the plugin menus system. You can 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", + "Andy Thomas", + "Andy Thomas", + "1999", + "/Xtns/Plugin Details", + "", + PROC_EXTENSION, + nargs, 0, + args, NULL); +} + +static void +run (char *name, + int nparams, + GParam *param, + int *nreturn_vals, + GParam **return_vals) +{ + static GParam values[2]; + GRunModeType run_mode; + GtkWidget * plugin_dialog; + + run_mode = param[0].data.d_int32; + + *nreturn_vals = 1; + *return_vals = values; + values[0].type = PARAM_STATUS; + values[0].data.d_status = STATUS_CALLING_ERROR; + + if (strcmp (name, "plug_in_details") == 0) + { + *nreturn_vals = 1; + + values[0].data.d_status = STATUS_SUCCESS; + + plugin_dialog = gimp_plugin_desc(); + gtk_widget_show(plugin_dialog); + gtk_main (); + gdk_flush (); + } +} + + +typedef struct +{ + GtkWidget * dlg; + GtkWidget * clist; + GtkWidget * ctree; + GtkWidget * search_entry; + GtkWidget * descr_scroll; + GtkWidget * name_button; + GtkWidget * blurb_button; + GtkWidget * scrolled_win; + GtkWidget * ctree_scrolled_win; + GtkWidget * info_table; + GtkWidget * info_align; + gint num_plugins; + gint ctree_row; + gint clist_row; + gboolean details_showing; +} PLUGINDESC,*PLUGINDESCP; + +PLUGINDESCP plugindesc = NULL; + +typedef struct +{ + gchar *menu; + gchar *accel; + gchar *prog; + gchar *types; + gchar *realname; + gint instime; +} PINFO, *PINFOP; + +static void +dialog_close_callback (GtkWidget *widget, + gpointer data) + /* end of the dialog */ +{ + PLUGINDESCP pdesc = data; + gtk_widget_destroy(pdesc->dlg); + gtk_main_quit (); +} + +static void +details_callback (GtkWidget *widget, + gpointer data) +{ + /* Show or hide the details window */ + PLUGINDESCP pdesc = data; + GtkLabel *lab = GTK_LABEL(GTK_BIN (widget)->child); + + if(pdesc->details_showing == FALSE) + { + gtk_label_set_text(lab,"Details <<<"); + gtk_widget_show (pdesc->descr_scroll); + pdesc->details_showing = TRUE; + } + else + { + gtk_label_set_text(lab,"Details >>>"); + gtk_widget_hide (pdesc->descr_scroll); + pdesc->details_showing = FALSE; + } +} + +static gchar * +format_menu_path(gchar *s) +{ + gchar ** str_array; + gchar *newstr = NULL; + + if(!s) + return s; + + str_array = g_strsplit(s,"/",0); + + newstr = g_strjoinv("->",str_array); + + g_strfreev(str_array); + + return newstr; +} + +static gint +procedure_general_select_callback (PLUGINDESCP pdesc, + PINFOP pinfo) +{ + gchar *selected_proc_blurb; + gchar *selected_proc_help; + gchar *selected_proc_author; + gchar *selected_proc_copyright; + gchar *selected_proc_date; + gint selected_proc_type; + gint selected_nparams; + gint selected_nreturn_vals; + GParamDef *selected_params; + GParamDef *selected_return_vals; + GtkWidget *label; + GtkWidget *help; + GtkWidget *text; + GtkWidget *vscrollbar; + GtkWidget *old_table; + GtkWidget *old_align; + gint table_row = 0; + + g_return_val_if_fail (pdesc != NULL, FALSE); + + g_return_val_if_fail (pinfo != NULL, FALSE); + + selected_proc_blurb = NULL; + selected_proc_help = NULL; + selected_proc_author = NULL; + selected_proc_copyright = NULL; + selected_proc_date = NULL; + selected_proc_type = 0; + selected_nparams = 0; + selected_nreturn_vals = 0; + selected_params = NULL; + selected_return_vals = NULL; + + gimp_query_procedure (pinfo->realname, + &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); + + old_table = pdesc->info_table; + old_align = pdesc->info_align; + + pdesc->info_table = gtk_table_new(10 ,5 , FALSE); + pdesc->info_align = gtk_alignment_new (0.5, 0.5, 0, 0); + + gtk_table_set_col_spacings( GTK_TABLE(pdesc->info_table), 3); + + /* Number of plugins */ + + label = gtk_label_new(g_strdup_printf(" Number of plugin interfaces :%d",pdesc->num_plugins)); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + + /* menu path */ + + label = gtk_label_new("Menu path :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 0); + gtk_widget_show(label); + + label = gtk_label_new(format_menu_path(pinfo->menu)); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + /* show the name */ + + label = gtk_label_new("Name :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + + label = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(label),pinfo->realname); + gtk_entry_set_editable(GTK_ENTRY(label), FALSE); + gtk_table_attach (GTK_TABLE(pdesc->info_table), label, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + /* show the description */ + + label = gtk_label_new("Blurb :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 0); + gtk_widget_show(label); + + label = gtk_label_new(selected_proc_blurb); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + /* show the help */ + if ((selected_proc_help) && (strlen(selected_proc_help) > 1)) + { + label = gtk_label_new("Help :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, + GTK_FILL, GTK_FILL, 3, 0); + gtk_widget_show(label); + + 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); + gtk_table_attach (GTK_TABLE (pdesc->info_table), help, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 0); + gtk_widget_show (help); + table_row++; + + text = gtk_text_new (NULL, NULL); + gtk_text_set_editable (GTK_TEXT (text), FALSE); + gtk_text_set_word_wrap(GTK_TEXT(text), TRUE); + gtk_widget_set_usize (text, -1, 60); + gtk_table_attach (GTK_TABLE (help), text, 0, 1, 0, 1, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0); + gtk_widget_show (text); + + vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj); + gtk_table_attach (GTK_TABLE (help), vscrollbar, 1, 2, 0, 1, + GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0); + gtk_widget_show (vscrollbar); + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + + gtk_text_freeze (GTK_TEXT (text)); + gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, + selected_proc_help, -1); + gtk_text_thaw (GTK_TEXT (text)); + + table_row++; + } + + /* show the type */ + + label = gtk_label_new("Type :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + + label = gtk_label_new(proc_type_str[selected_proc_type]); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + /* Remove old and replace with new */ + + if(old_table) + gtk_widget_destroy(old_table); + + if(old_align) + gtk_widget_destroy(old_align); + + gtk_container_add (GTK_CONTAINER (pdesc->info_align),pdesc->info_table); + + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (pdesc->descr_scroll), + pdesc->info_align); + + 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) + g_free(selected_proc_help); + 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); + + + return FALSE; +} + +static void +expand_to(PLUGINDESCP pdesc,GtkCTreeNode * parent) +{ + if(parent) + { + expand_to(pdesc,(GTK_CTREE_ROW(parent))->parent); + gtk_ctree_expand(GTK_CTREE(pdesc->ctree),parent); + } +} + +static gint +procedure_clist_select_callback (GtkWidget *widget, + gint row, + gint column, + GdkEventButton * bevent, + gpointer data) +{ + PINFOP pinfo; + GtkCTreeNode * found_node; + PLUGINDESCP pdesc = data; + + g_return_val_if_fail (pdesc != NULL, FALSE); + + pinfo = (PINFOP)gtk_clist_get_row_data (GTK_CLIST (widget), row); + + if(!pinfo) + return FALSE; + + /* Must select the correct one in the ctree structure */ + + found_node = gtk_ctree_find_by_row_data(GTK_CTREE(pdesc->ctree),NULL,pinfo); + + if(found_node) + { + GtkCTreeRow *ctr; + GtkCTreeNode *parent; + int sel_row; + + /* Make sure this is expanded */ + + ctr = GTK_CTREE_ROW(found_node); + + parent = GTK_CTREE_NODE(ctr->parent); + + expand_to(pdesc,parent); + + sel_row = gtk_clist_find_row_from_data(GTK_CLIST(pdesc->ctree),pinfo); + + gtk_widget_hide(pdesc->ctree); + gtk_widget_show(pdesc->ctree); + + gtk_signal_handler_block_by_func(GTK_OBJECT(pdesc->ctree),(GtkSignalFunc)procedure_ctree_select_callback,pdesc); + + + gtk_clist_select_row(GTK_CLIST(pdesc->ctree),sel_row,-1); + gtk_ctree_select(GTK_CTREE(pdesc->ctree),found_node); + + gtk_clist_moveto(GTK_CLIST(pdesc->ctree), + sel_row, + 0, + 0.5,0.5); + + gtk_signal_handler_unblock_by_func(GTK_OBJECT(pdesc->ctree),(GtkSignalFunc)procedure_ctree_select_callback,pdesc); + + pdesc->ctree_row = sel_row; + } + else + { + g_warning("Failed to find node in ctree"); + } + + return procedure_general_select_callback (pdesc,pinfo); +} + +/* This was an attempt to get around a problem in gtk + * where the scroll windows that contain ctree and clist + * refuse to respond to the moveto funcions unless the + * widgets are visible. + * Still did not work 100% even after this. + * Note the scrollbars are in the correct position but the + * widget needs to be redrawn at the correct location. + */ + +static gint +page_select_callback (GtkNotebook *notebook, + GtkNotebookPage *page, + guint page_num, + gpointer data) +{ + PLUGINDESCP pdesc = data; + + if(page_num == 0) + { + gtk_clist_select_row(GTK_CLIST(pdesc->clist),pdesc->clist_row,-1); + gtk_clist_moveto(GTK_CLIST(pdesc->clist), + pdesc->clist_row, + 0, + 0.5,0.5); + } + else + { + gtk_clist_select_row(GTK_CLIST(pdesc->ctree),pdesc->ctree_row,-1); + gtk_clist_moveto(GTK_CLIST(pdesc->ctree), + pdesc->ctree_row, + 0, + 0.5,0.5); + } + return FALSE; +} + +static gint +procedure_ctree_select_callback (GtkWidget *widget, + GtkWidget *row, + gint column, + gpointer data) +{ + PINFOP pinfo; + PLUGINDESCP pdesc; + gboolean is_leaf; + gint sel_row; + + /* row is not a leaf the we have no interest in it */ + + gtk_ctree_get_node_info(GTK_CTREE(widget), + GTK_CTREE_NODE(row), + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &is_leaf, + NULL); + + if(!is_leaf) + { + return FALSE; + } + + pdesc = data; + + pinfo = (PINFOP)gtk_ctree_node_get_row_data (GTK_CTREE(widget),GTK_CTREE_NODE(row)); + + + /* Must set clist to this one */ + /* Block signals */ + + gtk_signal_handler_block_by_func(GTK_OBJECT(pdesc->clist),(GtkSignalFunc)procedure_clist_select_callback,pdesc); + + sel_row = gtk_clist_find_row_from_data(GTK_CLIST(pdesc->clist),pinfo); + gtk_clist_select_row(GTK_CLIST(pdesc->clist),sel_row,-1); + gtk_clist_moveto(GTK_CLIST(pdesc->clist), + sel_row, + 0, + 0.5,0.5); + + gtk_signal_handler_unblock_by_func(GTK_OBJECT(pdesc->clist),(GtkSignalFunc)procedure_clist_select_callback,pdesc); + + pdesc->clist_row = sel_row; + + return procedure_general_select_callback (pdesc,pinfo); +} + +static void +pinfo_free(gpointer p) +{ + PINFOP pinfo = p; + + + g_free(pinfo->menu); + g_free(pinfo->accel); + g_free(pinfo->prog); + g_free(pinfo->types); + g_free(pinfo->realname); + g_free(pinfo); +} + +static GtkCTreeNode* +get_parent(PLUGINDESCP pdesc,GHashTable * ghash,gchar *mpath) +{ + GtkCTreeNode *parent; + GtkCTreeNode *last_parent; + gchar *tmp_ptr; + gchar *str_ptr; + gchar *leaf_ptr; + gchar *labels[3]; + + if(mpath == NULL) + return NULL; /* Parent is root */ + + parent = g_hash_table_lookup(ghash,mpath); + + if(parent) + { + /* found node */ + return (parent); + } + + /* Next one up */ + tmp_ptr = g_strdup(mpath); + + str_ptr = strrchr(tmp_ptr,'/'); + + if(str_ptr == NULL) + { + /* printf("Root node for %s\n",mpath); */ + leaf_ptr = mpath; + tmp_ptr = ""; + last_parent = NULL; + } + else + { + leaf_ptr = g_strdup(str_ptr+1); + + *str_ptr = '\000'; + + last_parent = get_parent(pdesc,ghash,tmp_ptr); + } + + labels[0] = g_strdup(leaf_ptr); + labels[1] = g_strdup(""); + labels[2] = g_strdup(""); + + /* printf("get_parent::creating node %s under %s\n",leaf_ptr,tmp_ptr); */ + + parent = gtk_ctree_insert_node(GTK_CTREE(pdesc->ctree), + last_parent, + NULL, + labels, + 4, + NULL, + NULL, + NULL, + NULL, + FALSE, + FALSE); + + g_hash_table_insert(ghash,mpath,parent); + + return parent; +} + +static void +insert_into_ctree(PLUGINDESCP pdesc,gchar *name, + gchar *xtimestr, + gchar *menu_str, + gchar *types_str, + GHashTable * ghash, + PINFOP pinfo) +{ + gchar *labels[3]; + gchar *str_ptr; + gchar *tmp_ptr; + gchar *leaf_ptr; + GtkCTreeNode *parent = NULL; + GtkCTreeNode *leaf_node = NULL; + + /* Find all nodes */ + /* Last one is the leaf part */ + + tmp_ptr = g_strdup(menu_str); + + str_ptr = strrchr(tmp_ptr,'/'); + + if(str_ptr == NULL) + return; /* No node */ + + leaf_ptr = g_strdup(str_ptr+1); + + *str_ptr = '\000'; + + /* printf("inserting %s...\n",menu_str); */ + + parent = get_parent(pdesc,ghash,tmp_ptr); + + /* Last was a leaf */ + /* printf("found leaf %s parent = %p\n",leaf_ptr,parent); */ + labels[0] = g_strdup(name); + labels[1] = g_strdup(xtimestr); + labels[2] = g_strdup(types_str); + + leaf_node = gtk_ctree_insert_node(GTK_CTREE(pdesc->ctree), + parent, + NULL, + labels, + 4, + NULL, + NULL, + NULL, + NULL, + TRUE, + FALSE); + + gtk_ctree_node_set_row_data(GTK_CTREE(pdesc->ctree),leaf_node,pinfo); + +} + +static void +get_plugin_info(PLUGINDESCP pdesc,gchar *search_text) +{ + GParam *return_vals; + int nreturn_vals; + gint row_count = 0; + gchar **menu_strs; + gchar **accel_strs; + gchar **prog_strs; + gchar **types_strs; + gchar **realname_strs; + gint *time_ints; + + GHashTable* ghash = g_hash_table_new(g_str_hash, g_str_equal); + + if(!search_text) + search_text = ""; + + return_vals = gimp_run_procedure ("gimp_plugins_query", + &nreturn_vals, + PARAM_STRING,search_text, + PARAM_END); + + if (return_vals[0].data.d_status == STATUS_SUCCESS) + { + int loop; + pdesc->num_plugins = return_vals[1].data.d_int32; + 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; + + for (loop = 0; loop < return_vals[1].data.d_int32; loop++) + { + PINFOP pinfo; + gchar *labels[4]; + 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) + { + x = localtime(&tx); + ret = strftime(xtimestr,sizeof(xtimestr), "%c",x); + xtimestr[ret] = 0; + } + 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]); + + labels[0] = g_strdup(name); + labels[1] = g_strdup(xtimestr); + labels[2] = g_strdup(menu_strs[loop]); + labels[3] = g_strdup(types_strs[loop]); + + gtk_clist_insert (GTK_CLIST (GTK_CLIST(pdesc->clist)), row_count, + labels); + + gtk_clist_set_row_data_full(GTK_CLIST(pdesc->clist), row_count, + pinfo,pinfo_free); + + row_count++; + + /* Now do the tree view.... */ + insert_into_ctree(pdesc, + name, + xtimestr, + menu_strs[loop], + types_strs[loop], + ghash, + pinfo); + } + } + + gimp_destroy_params (return_vals, nreturn_vals); +} + +static void +dialog_search_callback (GtkWidget *widget, + gpointer data) +{ + PLUGINDESCP pdesc = data; + gchar *search_text = NULL; + + if(widget != NULL) + { + /* The result of a button press... read entry data */ + search_text = gtk_entry_get_text(GTK_ENTRY(plugindesc->search_entry)); + } + + gtk_clist_freeze(GTK_CLIST(pdesc->ctree)); + gtk_clist_clear(GTK_CLIST(pdesc->ctree)); + gtk_clist_freeze(GTK_CLIST(pdesc->clist)); + gtk_clist_clear(GTK_CLIST(pdesc->clist)); + + get_plugin_info(pdesc,search_text); + + gtk_clist_columns_autosize(GTK_CLIST(plugindesc->clist)); + + gtk_clist_sort(GTK_CLIST(pdesc->clist)); + gtk_clist_thaw(GTK_CLIST(pdesc->clist)); + gtk_ctree_sort_recursive(GTK_CTREE(pdesc->ctree),NULL); + gtk_clist_thaw(GTK_CLIST(pdesc->ctree)); +} + +static gint +date_sort(GtkCList *clist, + gconstpointer ptr1, + gconstpointer ptr2) +{ + GtkCListRow *row1 = (GtkCListRow *) ptr1; + GtkCListRow *row2 = (GtkCListRow *) ptr2; + + /* Get the data for the row */ + PINFOP row1_pinfo = row1->data; + PINFOP row2_pinfo = row2->data; + + /* Want to sort on the date field */ + + if(row2_pinfo->instime < row1_pinfo->instime) + { + return(-1); + } + + if(row2_pinfo->instime > row1_pinfo->instime) + { + return(1); + } + + return(0); +} + +static void +clist_click_column (GtkCList *clist, gint column, gpointer data) +{ + if (column == 1) + { + gtk_clist_set_compare_func(clist,date_sort); + } + else + { + gtk_clist_set_compare_func(clist,NULL); /* Set back to default */ + } + + if (column == clist->sort_column) + { + if (clist->sort_type == GTK_SORT_ASCENDING) + clist->sort_type = GTK_SORT_DESCENDING; + else + clist->sort_type = GTK_SORT_ASCENDING; + } + else + gtk_clist_set_sort_column (clist, column); + + gtk_clist_sort (clist); +} + + +static GtkWidget * +gimp_plugin_desc() +{ + GtkWidget *button; + GtkWidget *hbox,*searchhbox,*vbox; + GtkWidget *label,*notebook,*swindow; + gchar **argv; + gint argc; + gchar *clabels[4]; + + argc = 1; + argv = g_new (gchar *, 1); + argv[0] = g_strdup ("plugin_desc"); + + gtk_init (&argc, &argv); + gtk_rc_parse (gimp_gtkrc ()); + + plugindesc = g_new0(PLUGINDESC,1); + + /* the dialog box */ + + plugindesc->dlg = gtk_dialog_new(); + plugindesc->details_showing = FALSE; + + gtk_window_set_title (GTK_WINDOW (plugindesc->dlg), "Plugin Descriptions"); + gtk_window_position (GTK_WINDOW (plugindesc->dlg), GTK_WIN_POS_MOUSE); + gtk_signal_connect (GTK_OBJECT (plugindesc->dlg), "destroy", + (GtkSignalFunc) dialog_close_callback, + plugindesc); + gtk_window_set_policy(GTK_WINDOW (plugindesc->dlg),TRUE,TRUE,TRUE); + + /* hbox : left=notebook ; right=description */ + + hbox = gtk_hpaned_new(); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (plugindesc->dlg)->vbox), + hbox, TRUE, TRUE, 0); + gtk_widget_show (hbox); + + + /* left = vbox : the list and the search entry */ + + vbox = gtk_vbox_new( FALSE, 0 ); + gtk_container_border_width (GTK_CONTAINER (vbox), 3); + gtk_paned_add1 (GTK_PANED (hbox),vbox); + gtk_widget_show(vbox); + + /* left = notebook */ + + notebook = gtk_notebook_new(); + gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0); + + /* list : list in a scrolled_win */ + + clabels[0] = g_strdup("Name"); + clabels[1] = g_strdup("Ins Date"); + clabels[2] = g_strdup("Menu Path"); + clabels[3] = g_strdup("Image Types"); + plugindesc->clist = gtk_clist_new_with_titles(4,clabels); + + gtk_signal_connect (GTK_OBJECT (plugindesc->clist), "click_column", + (GtkSignalFunc) clist_click_column, NULL); + gtk_clist_column_titles_show(GTK_CLIST(plugindesc->clist)); + swindow = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_clist_set_selection_mode (GTK_CLIST (plugindesc->clist), + GTK_SELECTION_BROWSE); + + gtk_widget_set_usize(plugindesc->clist, DBL_LIST_WIDTH, DBL_HEIGHT); + gtk_signal_connect (GTK_OBJECT (plugindesc->clist), "select_row", + (GtkSignalFunc) procedure_clist_select_callback, + plugindesc); + + label = gtk_label_new("List view"); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook),swindow,label); + gtk_container_add (GTK_CONTAINER (swindow), plugindesc->clist); + gtk_widget_show(plugindesc->clist); + gtk_widget_show(swindow); + + /* notebook->ctree */ + clabels[0] = g_strdup("Menu Path/Name"); + clabels[1] = g_strdup("Ins Date"); + clabels[2] = g_strdup("Image Types"); + plugindesc->ctree = gtk_ctree_new_with_titles(3,0,clabels); + plugindesc->ctree_scrolled_win = + swindow = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_widget_set_usize(plugindesc->ctree, DBL_LIST_WIDTH, DBL_HEIGHT); + gtk_signal_connect (GTK_OBJECT (plugindesc->ctree), "tree_select_row", + (GtkSignalFunc) procedure_ctree_select_callback, + plugindesc); + label = gtk_label_new("Tree view"); + gtk_clist_set_column_auto_resize (GTK_CLIST (plugindesc->ctree), 0, TRUE); + gtk_clist_set_column_auto_resize (GTK_CLIST (plugindesc->ctree), 1, TRUE); + gtk_clist_set_column_auto_resize (GTK_CLIST (plugindesc->ctree), 2, TRUE); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook),swindow,label); + gtk_container_add (GTK_CONTAINER (swindow), plugindesc->ctree); + gtk_widget_show(plugindesc->ctree); + gtk_widget_show(swindow); + + gtk_signal_connect_after (GTK_OBJECT (notebook), "switch_page", + (GtkSignalFunc) page_select_callback, + plugindesc); + + gtk_widget_show(notebook); + + /* search entry & details button */ + + searchhbox = gtk_hbox_new(FALSE,0); + gtk_box_pack_start (GTK_BOX (vbox), + searchhbox, FALSE, TRUE, 0); + gtk_widget_show(searchhbox); + + label = gtk_label_new("Search :"); + gtk_misc_set_alignment( GTK_MISC(label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (searchhbox), + label, TRUE, TRUE, 0); + gtk_widget_show(label); + + plugindesc->search_entry = gtk_entry_new(); + gtk_box_pack_start (GTK_BOX (searchhbox), + plugindesc->search_entry, TRUE, TRUE, 0); + gtk_widget_show(plugindesc->search_entry); + + button = gtk_button_new_with_label ("Details >>>"); + gtk_widget_show(button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) details_callback, plugindesc); + gtk_box_pack_start (GTK_BOX (searchhbox), + button, TRUE, TRUE, 0); + + /* right = description */ + + plugindesc->descr_scroll = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (plugindesc->descr_scroll), + GTK_POLICY_ALWAYS, + GTK_POLICY_ALWAYS + ); + gtk_paned_add2 (GTK_PANED (hbox), plugindesc->descr_scroll); + gtk_widget_set_usize (plugindesc->descr_scroll, DBL_WIDTH - DBL_LIST_WIDTH, 0); + + /* buttons in dlg->action_area */ + + gtk_container_border_width (GTK_CONTAINER (GTK_DIALOG(plugindesc->dlg)->action_area), 0); + + plugindesc->name_button = gtk_button_new_with_label ("Search by name"); + GTK_WIDGET_SET_FLAGS (plugindesc->name_button, GTK_CAN_DEFAULT); + gtk_signal_connect (GTK_OBJECT (plugindesc->name_button), "clicked", + (GtkSignalFunc) dialog_search_callback, plugindesc); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (plugindesc->dlg)->action_area), + plugindesc->name_button , TRUE, TRUE, 0); + gtk_widget_show(plugindesc->name_button); + + + button = gtk_button_new_with_label ("Close"); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) dialog_close_callback, plugindesc); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (plugindesc->dlg)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + + + /* now build the list */ + dialog_search_callback( NULL, (gpointer)plugindesc); + + gtk_widget_show (plugindesc->clist); + gtk_widget_show (plugindesc->dlg); + + return plugindesc->dlg; +} + diff --git a/plug-ins/plugindetails/.cvsignore b/plug-ins/plugindetails/.cvsignore new file mode 100644 index 0000000000..4dd32f925f --- /dev/null +++ b/plug-ins/plugindetails/.cvsignore @@ -0,0 +1,6 @@ +Makefile.in +Makefile +.deps +_libs +.libs +plugindetails diff --git a/plug-ins/plugindetails/Makefile.am b/plug-ins/plugindetails/Makefile.am new file mode 100644 index 0000000000..0b3746b1d7 --- /dev/null +++ b/plug-ins/plugindetails/Makefile.am @@ -0,0 +1,35 @@ +## Process this file with automake to produce Makefile.in + +pluginlibdir = $(gimpplugindir)/plug-ins + +pluginlib_PROGRAMS = plugindetails + +plugindetails_SOURCES = \ + plugindetails.c + +INCLUDES = \ + -I$(top_srcdir) \ + $(GTK_CFLAGS) \ + -I$(includedir) + +LDADD = \ + $(top_builddir)/libgimp/libgimp.la \ + $(GTK_LIBS) + +DEPS = \ + $(top_builddir)/libgimp/libgimp.la + +plugindetails_DEPENDENCIES = $(DEPS) + +.PHONY: files + +files: + @files=`ls $(DISTFILES) 2> /dev/null`; for p in $$files; do \ + echo $$p; \ + done + @for subdir in $(SUBDIRS); do \ + files=`cd $$subdir; $(MAKE) files | grep -v "make\[[1-9]\]"`; \ + for file in $$files; do \ + echo $$subdir/$$file; \ + done; \ + done diff --git a/plug-ins/plugindetails/plugindetails.c b/plug-ins/plugindetails/plugindetails.c new file mode 100644 index 0000000000..fddbe758fc --- /dev/null +++ b/plug-ins/plugindetails/plugindetails.c @@ -0,0 +1,1097 @@ +/* + * 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 + * + * Note some portions of th UI comes from the dbbrowser plugin. + * 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. + */ + +#include +#include +#include +#include +#include +#include "gtk/gtk.h" +#include "libgimp/gimp.h" + +#define DBL_LIST_WIDTH 250 +#define DBL_WIDTH DBL_LIST_WIDTH+450 +#define DBL_HEIGHT 200 + +static char *proc_type_str[] = +{ + "Internal GIMP procedure", + "GIMP Plug-In", + "GIMP Extension", + "Temporary Procedure" +}; + + +/* Declare some local functions. + */ +static void query (void); +static void run (char *name, + int nparams, + GParam *param, + int *nreturn_vals, + GParam **return_vals); + +static GtkWidget * gimp_plugin_desc(); +static gint procedure_clist_select_callback (GtkWidget *widget, + gint row, + gint column, + GdkEventButton * bevent, + gpointer data); +static gint procedure_ctree_select_callback (GtkWidget *widget, + GtkWidget *row, + gint column, + gpointer data); + +GPlugInInfo PLUG_IN_INFO = +{ + NULL, /* init_proc */ + NULL, /* quit_proc */ + query, /* query_proc */ + run, /* run_proc */ +}; + + +MAIN () + +static void +query () +{ + static GParamDef args[] = + { + { PARAM_INT32, "run_mode", "Interactive, [non-interactive]" } + }; + + static int nargs = sizeof (args) / sizeof (args[0]); + + gimp_install_procedure ("plug_in_details", + "Displays plugin details", + "Helps browse the plugin menus system. You can 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", + "Andy Thomas", + "Andy Thomas", + "1999", + "/Xtns/Plugin Details", + "", + PROC_EXTENSION, + nargs, 0, + args, NULL); +} + +static void +run (char *name, + int nparams, + GParam *param, + int *nreturn_vals, + GParam **return_vals) +{ + static GParam values[2]; + GRunModeType run_mode; + GtkWidget * plugin_dialog; + + run_mode = param[0].data.d_int32; + + *nreturn_vals = 1; + *return_vals = values; + values[0].type = PARAM_STATUS; + values[0].data.d_status = STATUS_CALLING_ERROR; + + if (strcmp (name, "plug_in_details") == 0) + { + *nreturn_vals = 1; + + values[0].data.d_status = STATUS_SUCCESS; + + plugin_dialog = gimp_plugin_desc(); + gtk_widget_show(plugin_dialog); + gtk_main (); + gdk_flush (); + } +} + + +typedef struct +{ + GtkWidget * dlg; + GtkWidget * clist; + GtkWidget * ctree; + GtkWidget * search_entry; + GtkWidget * descr_scroll; + GtkWidget * name_button; + GtkWidget * blurb_button; + GtkWidget * scrolled_win; + GtkWidget * ctree_scrolled_win; + GtkWidget * info_table; + GtkWidget * info_align; + gint num_plugins; + gint ctree_row; + gint clist_row; + gboolean details_showing; +} PLUGINDESC,*PLUGINDESCP; + +PLUGINDESCP plugindesc = NULL; + +typedef struct +{ + gchar *menu; + gchar *accel; + gchar *prog; + gchar *types; + gchar *realname; + gint instime; +} PINFO, *PINFOP; + +static void +dialog_close_callback (GtkWidget *widget, + gpointer data) + /* end of the dialog */ +{ + PLUGINDESCP pdesc = data; + gtk_widget_destroy(pdesc->dlg); + gtk_main_quit (); +} + +static void +details_callback (GtkWidget *widget, + gpointer data) +{ + /* Show or hide the details window */ + PLUGINDESCP pdesc = data; + GtkLabel *lab = GTK_LABEL(GTK_BIN (widget)->child); + + if(pdesc->details_showing == FALSE) + { + gtk_label_set_text(lab,"Details <<<"); + gtk_widget_show (pdesc->descr_scroll); + pdesc->details_showing = TRUE; + } + else + { + gtk_label_set_text(lab,"Details >>>"); + gtk_widget_hide (pdesc->descr_scroll); + pdesc->details_showing = FALSE; + } +} + +static gchar * +format_menu_path(gchar *s) +{ + gchar ** str_array; + gchar *newstr = NULL; + + if(!s) + return s; + + str_array = g_strsplit(s,"/",0); + + newstr = g_strjoinv("->",str_array); + + g_strfreev(str_array); + + return newstr; +} + +static gint +procedure_general_select_callback (PLUGINDESCP pdesc, + PINFOP pinfo) +{ + gchar *selected_proc_blurb; + gchar *selected_proc_help; + gchar *selected_proc_author; + gchar *selected_proc_copyright; + gchar *selected_proc_date; + gint selected_proc_type; + gint selected_nparams; + gint selected_nreturn_vals; + GParamDef *selected_params; + GParamDef *selected_return_vals; + GtkWidget *label; + GtkWidget *help; + GtkWidget *text; + GtkWidget *vscrollbar; + GtkWidget *old_table; + GtkWidget *old_align; + gint table_row = 0; + + g_return_val_if_fail (pdesc != NULL, FALSE); + + g_return_val_if_fail (pinfo != NULL, FALSE); + + selected_proc_blurb = NULL; + selected_proc_help = NULL; + selected_proc_author = NULL; + selected_proc_copyright = NULL; + selected_proc_date = NULL; + selected_proc_type = 0; + selected_nparams = 0; + selected_nreturn_vals = 0; + selected_params = NULL; + selected_return_vals = NULL; + + gimp_query_procedure (pinfo->realname, + &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); + + old_table = pdesc->info_table; + old_align = pdesc->info_align; + + pdesc->info_table = gtk_table_new(10 ,5 , FALSE); + pdesc->info_align = gtk_alignment_new (0.5, 0.5, 0, 0); + + gtk_table_set_col_spacings( GTK_TABLE(pdesc->info_table), 3); + + /* Number of plugins */ + + label = gtk_label_new(g_strdup_printf(" Number of plugin interfaces :%d",pdesc->num_plugins)); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + + /* menu path */ + + label = gtk_label_new("Menu path :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 0); + gtk_widget_show(label); + + label = gtk_label_new(format_menu_path(pinfo->menu)); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + /* show the name */ + + label = gtk_label_new("Name :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + + label = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(label),pinfo->realname); + gtk_entry_set_editable(GTK_ENTRY(label), FALSE); + gtk_table_attach (GTK_TABLE(pdesc->info_table), label, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + /* show the description */ + + label = gtk_label_new("Blurb :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 0); + gtk_widget_show(label); + + label = gtk_label_new(selected_proc_blurb); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + /* show the help */ + if ((selected_proc_help) && (strlen(selected_proc_help) > 1)) + { + label = gtk_label_new("Help :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, + GTK_FILL, GTK_FILL, 3, 0); + gtk_widget_show(label); + + 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); + gtk_table_attach (GTK_TABLE (pdesc->info_table), help, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 0); + gtk_widget_show (help); + table_row++; + + text = gtk_text_new (NULL, NULL); + gtk_text_set_editable (GTK_TEXT (text), FALSE); + gtk_text_set_word_wrap(GTK_TEXT(text), TRUE); + gtk_widget_set_usize (text, -1, 60); + gtk_table_attach (GTK_TABLE (help), text, 0, 1, 0, 1, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0); + gtk_widget_show (text); + + vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj); + gtk_table_attach (GTK_TABLE (help), vscrollbar, 1, 2, 0, 1, + GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0); + gtk_widget_show (vscrollbar); + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + + gtk_text_freeze (GTK_TEXT (text)); + gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, + selected_proc_help, -1); + gtk_text_thaw (GTK_TEXT (text)); + + table_row++; + } + + /* show the type */ + + label = gtk_label_new("Type :"); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 1, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + + label = gtk_label_new(proc_type_str[selected_proc_type]); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 1, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show(label); + table_row++; + + label = gtk_hseparator_new(); /* ok, not really a label ... :) */ + gtk_table_attach (GTK_TABLE (pdesc->info_table), label, + 0, 4, table_row, table_row+1, GTK_FILL, GTK_FILL, 3, 6); + gtk_widget_show(label); + table_row++; + + /* Remove old and replace with new */ + + if(old_table) + gtk_widget_destroy(old_table); + + if(old_align) + gtk_widget_destroy(old_align); + + gtk_container_add (GTK_CONTAINER (pdesc->info_align),pdesc->info_table); + + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (pdesc->descr_scroll), + pdesc->info_align); + + 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) + g_free(selected_proc_help); + 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); + + + return FALSE; +} + +static void +expand_to(PLUGINDESCP pdesc,GtkCTreeNode * parent) +{ + if(parent) + { + expand_to(pdesc,(GTK_CTREE_ROW(parent))->parent); + gtk_ctree_expand(GTK_CTREE(pdesc->ctree),parent); + } +} + +static gint +procedure_clist_select_callback (GtkWidget *widget, + gint row, + gint column, + GdkEventButton * bevent, + gpointer data) +{ + PINFOP pinfo; + GtkCTreeNode * found_node; + PLUGINDESCP pdesc = data; + + g_return_val_if_fail (pdesc != NULL, FALSE); + + pinfo = (PINFOP)gtk_clist_get_row_data (GTK_CLIST (widget), row); + + if(!pinfo) + return FALSE; + + /* Must select the correct one in the ctree structure */ + + found_node = gtk_ctree_find_by_row_data(GTK_CTREE(pdesc->ctree),NULL,pinfo); + + if(found_node) + { + GtkCTreeRow *ctr; + GtkCTreeNode *parent; + int sel_row; + + /* Make sure this is expanded */ + + ctr = GTK_CTREE_ROW(found_node); + + parent = GTK_CTREE_NODE(ctr->parent); + + expand_to(pdesc,parent); + + sel_row = gtk_clist_find_row_from_data(GTK_CLIST(pdesc->ctree),pinfo); + + gtk_widget_hide(pdesc->ctree); + gtk_widget_show(pdesc->ctree); + + gtk_signal_handler_block_by_func(GTK_OBJECT(pdesc->ctree),(GtkSignalFunc)procedure_ctree_select_callback,pdesc); + + + gtk_clist_select_row(GTK_CLIST(pdesc->ctree),sel_row,-1); + gtk_ctree_select(GTK_CTREE(pdesc->ctree),found_node); + + gtk_clist_moveto(GTK_CLIST(pdesc->ctree), + sel_row, + 0, + 0.5,0.5); + + gtk_signal_handler_unblock_by_func(GTK_OBJECT(pdesc->ctree),(GtkSignalFunc)procedure_ctree_select_callback,pdesc); + + pdesc->ctree_row = sel_row; + } + else + { + g_warning("Failed to find node in ctree"); + } + + return procedure_general_select_callback (pdesc,pinfo); +} + +/* This was an attempt to get around a problem in gtk + * where the scroll windows that contain ctree and clist + * refuse to respond to the moveto funcions unless the + * widgets are visible. + * Still did not work 100% even after this. + * Note the scrollbars are in the correct position but the + * widget needs to be redrawn at the correct location. + */ + +static gint +page_select_callback (GtkNotebook *notebook, + GtkNotebookPage *page, + guint page_num, + gpointer data) +{ + PLUGINDESCP pdesc = data; + + if(page_num == 0) + { + gtk_clist_select_row(GTK_CLIST(pdesc->clist),pdesc->clist_row,-1); + gtk_clist_moveto(GTK_CLIST(pdesc->clist), + pdesc->clist_row, + 0, + 0.5,0.5); + } + else + { + gtk_clist_select_row(GTK_CLIST(pdesc->ctree),pdesc->ctree_row,-1); + gtk_clist_moveto(GTK_CLIST(pdesc->ctree), + pdesc->ctree_row, + 0, + 0.5,0.5); + } + return FALSE; +} + +static gint +procedure_ctree_select_callback (GtkWidget *widget, + GtkWidget *row, + gint column, + gpointer data) +{ + PINFOP pinfo; + PLUGINDESCP pdesc; + gboolean is_leaf; + gint sel_row; + + /* row is not a leaf the we have no interest in it */ + + gtk_ctree_get_node_info(GTK_CTREE(widget), + GTK_CTREE_NODE(row), + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &is_leaf, + NULL); + + if(!is_leaf) + { + return FALSE; + } + + pdesc = data; + + pinfo = (PINFOP)gtk_ctree_node_get_row_data (GTK_CTREE(widget),GTK_CTREE_NODE(row)); + + + /* Must set clist to this one */ + /* Block signals */ + + gtk_signal_handler_block_by_func(GTK_OBJECT(pdesc->clist),(GtkSignalFunc)procedure_clist_select_callback,pdesc); + + sel_row = gtk_clist_find_row_from_data(GTK_CLIST(pdesc->clist),pinfo); + gtk_clist_select_row(GTK_CLIST(pdesc->clist),sel_row,-1); + gtk_clist_moveto(GTK_CLIST(pdesc->clist), + sel_row, + 0, + 0.5,0.5); + + gtk_signal_handler_unblock_by_func(GTK_OBJECT(pdesc->clist),(GtkSignalFunc)procedure_clist_select_callback,pdesc); + + pdesc->clist_row = sel_row; + + return procedure_general_select_callback (pdesc,pinfo); +} + +static void +pinfo_free(gpointer p) +{ + PINFOP pinfo = p; + + + g_free(pinfo->menu); + g_free(pinfo->accel); + g_free(pinfo->prog); + g_free(pinfo->types); + g_free(pinfo->realname); + g_free(pinfo); +} + +static GtkCTreeNode* +get_parent(PLUGINDESCP pdesc,GHashTable * ghash,gchar *mpath) +{ + GtkCTreeNode *parent; + GtkCTreeNode *last_parent; + gchar *tmp_ptr; + gchar *str_ptr; + gchar *leaf_ptr; + gchar *labels[3]; + + if(mpath == NULL) + return NULL; /* Parent is root */ + + parent = g_hash_table_lookup(ghash,mpath); + + if(parent) + { + /* found node */ + return (parent); + } + + /* Next one up */ + tmp_ptr = g_strdup(mpath); + + str_ptr = strrchr(tmp_ptr,'/'); + + if(str_ptr == NULL) + { + /* printf("Root node for %s\n",mpath); */ + leaf_ptr = mpath; + tmp_ptr = ""; + last_parent = NULL; + } + else + { + leaf_ptr = g_strdup(str_ptr+1); + + *str_ptr = '\000'; + + last_parent = get_parent(pdesc,ghash,tmp_ptr); + } + + labels[0] = g_strdup(leaf_ptr); + labels[1] = g_strdup(""); + labels[2] = g_strdup(""); + + /* printf("get_parent::creating node %s under %s\n",leaf_ptr,tmp_ptr); */ + + parent = gtk_ctree_insert_node(GTK_CTREE(pdesc->ctree), + last_parent, + NULL, + labels, + 4, + NULL, + NULL, + NULL, + NULL, + FALSE, + FALSE); + + g_hash_table_insert(ghash,mpath,parent); + + return parent; +} + +static void +insert_into_ctree(PLUGINDESCP pdesc,gchar *name, + gchar *xtimestr, + gchar *menu_str, + gchar *types_str, + GHashTable * ghash, + PINFOP pinfo) +{ + gchar *labels[3]; + gchar *str_ptr; + gchar *tmp_ptr; + gchar *leaf_ptr; + GtkCTreeNode *parent = NULL; + GtkCTreeNode *leaf_node = NULL; + + /* Find all nodes */ + /* Last one is the leaf part */ + + tmp_ptr = g_strdup(menu_str); + + str_ptr = strrchr(tmp_ptr,'/'); + + if(str_ptr == NULL) + return; /* No node */ + + leaf_ptr = g_strdup(str_ptr+1); + + *str_ptr = '\000'; + + /* printf("inserting %s...\n",menu_str); */ + + parent = get_parent(pdesc,ghash,tmp_ptr); + + /* Last was a leaf */ + /* printf("found leaf %s parent = %p\n",leaf_ptr,parent); */ + labels[0] = g_strdup(name); + labels[1] = g_strdup(xtimestr); + labels[2] = g_strdup(types_str); + + leaf_node = gtk_ctree_insert_node(GTK_CTREE(pdesc->ctree), + parent, + NULL, + labels, + 4, + NULL, + NULL, + NULL, + NULL, + TRUE, + FALSE); + + gtk_ctree_node_set_row_data(GTK_CTREE(pdesc->ctree),leaf_node,pinfo); + +} + +static void +get_plugin_info(PLUGINDESCP pdesc,gchar *search_text) +{ + GParam *return_vals; + int nreturn_vals; + gint row_count = 0; + gchar **menu_strs; + gchar **accel_strs; + gchar **prog_strs; + gchar **types_strs; + gchar **realname_strs; + gint *time_ints; + + GHashTable* ghash = g_hash_table_new(g_str_hash, g_str_equal); + + if(!search_text) + search_text = ""; + + return_vals = gimp_run_procedure ("gimp_plugins_query", + &nreturn_vals, + PARAM_STRING,search_text, + PARAM_END); + + if (return_vals[0].data.d_status == STATUS_SUCCESS) + { + int loop; + pdesc->num_plugins = return_vals[1].data.d_int32; + 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; + + for (loop = 0; loop < return_vals[1].data.d_int32; loop++) + { + PINFOP pinfo; + gchar *labels[4]; + 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) + { + x = localtime(&tx); + ret = strftime(xtimestr,sizeof(xtimestr), "%c",x); + xtimestr[ret] = 0; + } + 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]); + + labels[0] = g_strdup(name); + labels[1] = g_strdup(xtimestr); + labels[2] = g_strdup(menu_strs[loop]); + labels[3] = g_strdup(types_strs[loop]); + + gtk_clist_insert (GTK_CLIST (GTK_CLIST(pdesc->clist)), row_count, + labels); + + gtk_clist_set_row_data_full(GTK_CLIST(pdesc->clist), row_count, + pinfo,pinfo_free); + + row_count++; + + /* Now do the tree view.... */ + insert_into_ctree(pdesc, + name, + xtimestr, + menu_strs[loop], + types_strs[loop], + ghash, + pinfo); + } + } + + gimp_destroy_params (return_vals, nreturn_vals); +} + +static void +dialog_search_callback (GtkWidget *widget, + gpointer data) +{ + PLUGINDESCP pdesc = data; + gchar *search_text = NULL; + + if(widget != NULL) + { + /* The result of a button press... read entry data */ + search_text = gtk_entry_get_text(GTK_ENTRY(plugindesc->search_entry)); + } + + gtk_clist_freeze(GTK_CLIST(pdesc->ctree)); + gtk_clist_clear(GTK_CLIST(pdesc->ctree)); + gtk_clist_freeze(GTK_CLIST(pdesc->clist)); + gtk_clist_clear(GTK_CLIST(pdesc->clist)); + + get_plugin_info(pdesc,search_text); + + gtk_clist_columns_autosize(GTK_CLIST(plugindesc->clist)); + + gtk_clist_sort(GTK_CLIST(pdesc->clist)); + gtk_clist_thaw(GTK_CLIST(pdesc->clist)); + gtk_ctree_sort_recursive(GTK_CTREE(pdesc->ctree),NULL); + gtk_clist_thaw(GTK_CLIST(pdesc->ctree)); +} + +static gint +date_sort(GtkCList *clist, + gconstpointer ptr1, + gconstpointer ptr2) +{ + GtkCListRow *row1 = (GtkCListRow *) ptr1; + GtkCListRow *row2 = (GtkCListRow *) ptr2; + + /* Get the data for the row */ + PINFOP row1_pinfo = row1->data; + PINFOP row2_pinfo = row2->data; + + /* Want to sort on the date field */ + + if(row2_pinfo->instime < row1_pinfo->instime) + { + return(-1); + } + + if(row2_pinfo->instime > row1_pinfo->instime) + { + return(1); + } + + return(0); +} + +static void +clist_click_column (GtkCList *clist, gint column, gpointer data) +{ + if (column == 1) + { + gtk_clist_set_compare_func(clist,date_sort); + } + else + { + gtk_clist_set_compare_func(clist,NULL); /* Set back to default */ + } + + if (column == clist->sort_column) + { + if (clist->sort_type == GTK_SORT_ASCENDING) + clist->sort_type = GTK_SORT_DESCENDING; + else + clist->sort_type = GTK_SORT_ASCENDING; + } + else + gtk_clist_set_sort_column (clist, column); + + gtk_clist_sort (clist); +} + + +static GtkWidget * +gimp_plugin_desc() +{ + GtkWidget *button; + GtkWidget *hbox,*searchhbox,*vbox; + GtkWidget *label,*notebook,*swindow; + gchar **argv; + gint argc; + gchar *clabels[4]; + + argc = 1; + argv = g_new (gchar *, 1); + argv[0] = g_strdup ("plugin_desc"); + + gtk_init (&argc, &argv); + gtk_rc_parse (gimp_gtkrc ()); + + plugindesc = g_new0(PLUGINDESC,1); + + /* the dialog box */ + + plugindesc->dlg = gtk_dialog_new(); + plugindesc->details_showing = FALSE; + + gtk_window_set_title (GTK_WINDOW (plugindesc->dlg), "Plugin Descriptions"); + gtk_window_position (GTK_WINDOW (plugindesc->dlg), GTK_WIN_POS_MOUSE); + gtk_signal_connect (GTK_OBJECT (plugindesc->dlg), "destroy", + (GtkSignalFunc) dialog_close_callback, + plugindesc); + gtk_window_set_policy(GTK_WINDOW (plugindesc->dlg),TRUE,TRUE,TRUE); + + /* hbox : left=notebook ; right=description */ + + hbox = gtk_hpaned_new(); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (plugindesc->dlg)->vbox), + hbox, TRUE, TRUE, 0); + gtk_widget_show (hbox); + + + /* left = vbox : the list and the search entry */ + + vbox = gtk_vbox_new( FALSE, 0 ); + gtk_container_border_width (GTK_CONTAINER (vbox), 3); + gtk_paned_add1 (GTK_PANED (hbox),vbox); + gtk_widget_show(vbox); + + /* left = notebook */ + + notebook = gtk_notebook_new(); + gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0); + + /* list : list in a scrolled_win */ + + clabels[0] = g_strdup("Name"); + clabels[1] = g_strdup("Ins Date"); + clabels[2] = g_strdup("Menu Path"); + clabels[3] = g_strdup("Image Types"); + plugindesc->clist = gtk_clist_new_with_titles(4,clabels); + + gtk_signal_connect (GTK_OBJECT (plugindesc->clist), "click_column", + (GtkSignalFunc) clist_click_column, NULL); + gtk_clist_column_titles_show(GTK_CLIST(plugindesc->clist)); + swindow = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_clist_set_selection_mode (GTK_CLIST (plugindesc->clist), + GTK_SELECTION_BROWSE); + + gtk_widget_set_usize(plugindesc->clist, DBL_LIST_WIDTH, DBL_HEIGHT); + gtk_signal_connect (GTK_OBJECT (plugindesc->clist), "select_row", + (GtkSignalFunc) procedure_clist_select_callback, + plugindesc); + + label = gtk_label_new("List view"); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook),swindow,label); + gtk_container_add (GTK_CONTAINER (swindow), plugindesc->clist); + gtk_widget_show(plugindesc->clist); + gtk_widget_show(swindow); + + /* notebook->ctree */ + clabels[0] = g_strdup("Menu Path/Name"); + clabels[1] = g_strdup("Ins Date"); + clabels[2] = g_strdup("Image Types"); + plugindesc->ctree = gtk_ctree_new_with_titles(3,0,clabels); + plugindesc->ctree_scrolled_win = + swindow = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_widget_set_usize(plugindesc->ctree, DBL_LIST_WIDTH, DBL_HEIGHT); + gtk_signal_connect (GTK_OBJECT (plugindesc->ctree), "tree_select_row", + (GtkSignalFunc) procedure_ctree_select_callback, + plugindesc); + label = gtk_label_new("Tree view"); + gtk_clist_set_column_auto_resize (GTK_CLIST (plugindesc->ctree), 0, TRUE); + gtk_clist_set_column_auto_resize (GTK_CLIST (plugindesc->ctree), 1, TRUE); + gtk_clist_set_column_auto_resize (GTK_CLIST (plugindesc->ctree), 2, TRUE); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook),swindow,label); + gtk_container_add (GTK_CONTAINER (swindow), plugindesc->ctree); + gtk_widget_show(plugindesc->ctree); + gtk_widget_show(swindow); + + gtk_signal_connect_after (GTK_OBJECT (notebook), "switch_page", + (GtkSignalFunc) page_select_callback, + plugindesc); + + gtk_widget_show(notebook); + + /* search entry & details button */ + + searchhbox = gtk_hbox_new(FALSE,0); + gtk_box_pack_start (GTK_BOX (vbox), + searchhbox, FALSE, TRUE, 0); + gtk_widget_show(searchhbox); + + label = gtk_label_new("Search :"); + gtk_misc_set_alignment( GTK_MISC(label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (searchhbox), + label, TRUE, TRUE, 0); + gtk_widget_show(label); + + plugindesc->search_entry = gtk_entry_new(); + gtk_box_pack_start (GTK_BOX (searchhbox), + plugindesc->search_entry, TRUE, TRUE, 0); + gtk_widget_show(plugindesc->search_entry); + + button = gtk_button_new_with_label ("Details >>>"); + gtk_widget_show(button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) details_callback, plugindesc); + gtk_box_pack_start (GTK_BOX (searchhbox), + button, TRUE, TRUE, 0); + + /* right = description */ + + plugindesc->descr_scroll = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (plugindesc->descr_scroll), + GTK_POLICY_ALWAYS, + GTK_POLICY_ALWAYS + ); + gtk_paned_add2 (GTK_PANED (hbox), plugindesc->descr_scroll); + gtk_widget_set_usize (plugindesc->descr_scroll, DBL_WIDTH - DBL_LIST_WIDTH, 0); + + /* buttons in dlg->action_area */ + + gtk_container_border_width (GTK_CONTAINER (GTK_DIALOG(plugindesc->dlg)->action_area), 0); + + plugindesc->name_button = gtk_button_new_with_label ("Search by name"); + GTK_WIDGET_SET_FLAGS (plugindesc->name_button, GTK_CAN_DEFAULT); + gtk_signal_connect (GTK_OBJECT (plugindesc->name_button), "clicked", + (GtkSignalFunc) dialog_search_callback, plugindesc); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (plugindesc->dlg)->action_area), + plugindesc->name_button , TRUE, TRUE, 0); + gtk_widget_show(plugindesc->name_button); + + + button = gtk_button_new_with_label ("Close"); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) dialog_close_callback, plugindesc); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (plugindesc->dlg)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + + + /* now build the list */ + dialog_search_callback( NULL, (gpointer)plugindesc); + + gtk_widget_show (plugindesc->clist); + gtk_widget_show (plugindesc->dlg); + + return plugindesc->dlg; +} +