Added byline
[anjuta.git] / plugins / project-wizard / druid.c
blob9c6f2023316d8c11104cc6c8a699fd5afa9885b1
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 druid.c
4 Copyright (C) 2004 Sebastien Granjoux
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 * All GUI functions
24 *---------------------------------------------------------------------------*/
26 #include <config.h>
28 #include "druid.h"
30 #include "plugin.h"
31 #include "header.h"
32 #include "property.h"
33 #include "parser.h"
34 #include "install.h"
36 #include <libanjuta/anjuta-debug.h>
37 #include <libanjuta/anjuta-utils.h>
38 #include <libanjuta/anjuta-autogen.h>
39 #include <libanjuta/interfaces/ianjuta-wizard.h>
40 #include <libanjuta/interfaces/ianjuta-editor.h>
41 #include <stdlib.h>
42 #include <glib/gi18n.h>
43 #include <glib.h>
44 #include <gdk/gdk.h>
46 #include <gtk/gtk.h>
48 #include <string.h>
50 /*---------------------------------------------------------------------------*/
52 #define PROJECT_WIZARD_DIRECTORY PACKAGE_DATA_DIR "/templates"
54 /* Default property name useable in wizard file
55 *---------------------------------------------------------------------------*/
57 #define ANJUTA_PROJECT_DIRECTORY_PROPERTY "AnjutaProjectDirectory"
58 #define DESTINATION_PROPERTY "Destination"
59 #define USER_NAME_PROPERTY "UserName"
60 #define AUTHOR_PROPERTY "Author"
61 #define EMAIL_ADDRESS_PROPERTY "EmailAddress"
62 #define EMAIL_PROPERTY "Email"
63 #define INDENT_WIDTH_PROPERTY "IndentWidth"
64 #define TAB_WIDTH_PROPERTY "TabWidth"
65 #define USE_TABS_PROPERTY "UseTabs"
67 /* Common editor preferences */
68 #define ANJUTA_PREF_SCHEMA_PREFIX "org.gnome.anjuta."
70 #define PROJECT_WIZARD_PREF_SCHEMA "plugins.project-wizard"
72 #define LAST_DIRECTORY "project-directory"
73 #define LAST_USER_NAME "user"
74 #define LAST_EMAIL "email"
76 /* Widget and signal name found in glade file
77 *---------------------------------------------------------------------------*/
79 #define GTK_BUILDER_UI_FILE PACKAGE_DATA_DIR "/glade/anjuta-project-wizard.ui"
81 #define NEW_PROJECT_DIALOG "druid_window"
82 #define PROJECT_LIST "project_list"
83 #define PROJECT_BOOK "project_book"
84 #define PROJECT_PAGE "project_page"
85 #define ERROR_PAGE "error_page"
86 #define ERROR_TITLE "error_title"
87 #define PROGRESS_PAGE "progress_page"
88 #define FINISH_PAGE "finish_page"
89 #define FINISH_TEXT "finish_text"
90 #define PROPERTY_PAGE "property_page"
91 #define PROPERTY_TITLE "property_title"
92 #define PROPERTY_TABLE "property_table"
93 #define ERROR_VBOX "error_vbox"
94 #define ERROR_ICON "error_icon"
95 #define ERROR_MESSAGE "error_message"
96 #define ERROR_DETAIL "error_detail"
99 #define PROJECT_PAGE_INDEX 0
101 /*---------------------------------------------------------------------------*/
103 struct _NPWDruid
105 GtkWindow* window;
107 GtkNotebook* project_book;
108 GtkWidget *error_page;
109 GtkWidget *error_title;
110 GtkBox *error_vbox;
111 GtkWidget *error_extra_widget;
112 GtkImage *error_icon;
113 GtkLabel *error_message;
114 GtkWidget *error_detail;
116 GtkWidget *project_page;
117 GtkWidget *progress_page;
118 GtkWidget *finish_page;
119 GtkWidget *finish_text;
121 const gchar* project_file;
122 NPWPlugin* plugin;
124 GQueue* page_list;
126 GHashTable* values;
127 NPWPageParser* parser;
128 GList* header_list;
129 NPWHeader* header;
130 gboolean no_selection;
131 AnjutaAutogen* gen;
132 gboolean busy;
135 /* column of the icon view */
136 enum {
137 PIXBUF_COLUMN,
138 TEXT_COLUMN,
139 DESC_COLUMN,
140 DATA_COLUMN
143 /* Helper functon
144 *---------------------------------------------------------------------------*/
146 /* Druid GUI functions
147 *---------------------------------------------------------------------------*/
149 static void
150 npw_druid_set_busy (NPWDruid *druid, gboolean busy_state)
152 if (druid->busy == busy_state)
153 return;
155 /* Set busy state */
156 if (busy_state)
157 anjuta_status_busy_push (anjuta_shell_get_status (ANJUTA_PLUGIN (druid->plugin)->shell, NULL));
158 else
159 anjuta_status_busy_pop (anjuta_shell_get_status (ANJUTA_PLUGIN (druid->plugin)->shell, NULL));
160 druid->busy = busy_state;
163 /* Create error page
164 *---------------------------------------------------------------------------*/
166 /* Fill dialog page */
167 static void
168 npw_druid_fill_error_page (NPWDruid* druid, GtkWidget *extra_widget, GtkMessageType type, const gchar *detail, const gchar *mesg,...)
170 GtkAssistant *assistant;
171 GtkWidget *page;
172 va_list args;
173 gchar *message;
174 const gchar *stock_id = NULL;
175 const gchar *title = NULL;
177 assistant = GTK_ASSISTANT (druid->window);
179 /* Add page to assistant after current one */
180 page = druid->error_page;
181 gtk_assistant_insert_page (assistant, page, gtk_assistant_get_current_page (assistant) + 1);
183 /* Set dialog kind */
184 switch (type)
186 case GTK_MESSAGE_INFO:
187 stock_id = GTK_STOCK_DIALOG_INFO;
188 title = _("Information");
189 break;
190 case GTK_MESSAGE_QUESTION:
191 stock_id = GTK_STOCK_DIALOG_QUESTION;
192 title = _("Warning");
193 break;
194 case GTK_MESSAGE_WARNING:
195 stock_id = GTK_STOCK_DIALOG_WARNING;
196 title = _("Warning");
197 break;
198 case GTK_MESSAGE_ERROR:
199 stock_id = GTK_STOCK_DIALOG_ERROR;
200 title = _("Error");
201 break;
202 case GTK_MESSAGE_OTHER:
203 title = _("Message");
204 break;
205 default:
206 g_warning ("Unknown GtkMessageType %u", type);
207 break;
209 gtk_label_set_text (GTK_LABEL (druid->error_title), title);
210 gtk_assistant_set_page_title (assistant, page, title);
211 if (type == GTK_MESSAGE_ERROR)
213 gtk_assistant_set_page_type (assistant, page, GTK_ASSISTANT_PAGE_CONTENT);
214 gtk_assistant_set_page_complete (assistant, page, FALSE);
216 else
218 gtk_assistant_set_page_type (assistant, page, GTK_ASSISTANT_PAGE_PROGRESS);
219 gtk_assistant_set_page_complete (assistant, page, TRUE);
221 gtk_image_set_from_stock (druid->error_icon, stock_id, GTK_ICON_SIZE_DIALOG);
223 /* Set message */
224 va_start (args, mesg);
225 message = g_strdup_vprintf (mesg, args);
226 va_end (args);
227 gtk_label_set_markup (druid->error_message, message);
228 g_free (message);
230 /* Set detail */
231 if (detail == NULL)
233 gtk_widget_hide (druid->error_detail);
235 else
237 GtkLabel *label;
239 gtk_widget_show (druid->error_detail);
240 label = GTK_LABEL (gtk_bin_get_child (GTK_BIN (druid->error_detail)));
241 gtk_label_set_text (label, detail);
244 if (druid->error_extra_widget)
245 gtk_widget_destroy (druid->error_extra_widget);
246 druid->error_extra_widget = NULL;
248 /* Set extra widget */
249 if (extra_widget)
251 gtk_box_pack_start (GTK_BOX (druid->error_vbox), extra_widget,
252 FALSE, FALSE, 10);
253 gtk_widget_show (extra_widget);
254 druid->error_extra_widget = extra_widget;
258 /* Create finish page
259 *---------------------------------------------------------------------------*/
261 static void
262 cb_druid_add_summary_property (NPWProperty* property, gpointer user_data)
264 GString* text = (GString*)user_data;
266 if (npw_property_get_options (property) & NPW_SUMMARY_OPTION)
268 g_string_append_printf (text, "%s %s\n",
269 npw_property_get_label (property),
270 npw_property_get_value (property));
274 /* Fill last page (summary) */
275 static void
276 npw_druid_fill_summary_page (NPWDruid* druid)
278 NPWPage* page;
279 guint i;
280 GString* text;
281 GtkLabel* label;
283 text = g_string_new (NULL);
284 g_string_append_printf (text, "<b>%s</b>\n\n", _("Confirm the following information:"));
286 /* The project type is translated too, it is something like
287 * generic, GNOME applet, Makefile project... */
288 g_string_append_printf (text, _("Project Type: %s\n"), npw_header_get_name (druid->header));
290 for (i = 0; (page = g_queue_peek_nth (druid->page_list, i)) != NULL; ++i)
292 npw_page_foreach_property (page, (GFunc)cb_druid_add_summary_property, text);
295 label = GTK_LABEL (druid->finish_text);
296 gtk_label_set_markup (label, text->str);
297 g_string_free (text, TRUE);
299 gtk_assistant_set_page_complete (GTK_ASSISTANT (druid->window), druid->finish_page, TRUE);
302 /* Create project selection page
303 *---------------------------------------------------------------------------*/
305 /* Update selected project */
306 static void
307 on_druid_project_update_selected (GtkIconView* view, NPWDruid *druid)
309 GList *selected;
310 NPWHeader* header = NULL;
312 /* No item can be selected when the view is mapped */
313 selected = gtk_icon_view_get_selected_items (view);
314 if (selected != NULL)
316 GtkTreeIter iter;
317 GtkTreeModel *model;
319 model = gtk_icon_view_get_model (view);
320 if (gtk_tree_model_get_iter (model, &iter, (GtkTreePath *)selected->data))
322 gtk_tree_model_get (model, &iter, DATA_COLUMN, &header, -1);
324 gtk_tree_path_free ((GtkTreePath *)selected->data);
325 g_list_free (selected);
328 druid->header = header;
329 gtk_assistant_set_page_complete (GTK_ASSISTANT (druid->window), druid->project_page, header != NULL);
332 /* Add a project in the icon list */
333 static void
334 cb_druid_insert_project_icon (gpointer data, gpointer user_data)
336 NPWHeader *header = (NPWHeader *)data;
337 GtkListStore* store = GTK_LIST_STORE (user_data);
338 GtkTreeIter iter;
339 GdkPixbuf *pixbuf;
341 gtk_list_store_append (store, &iter);
342 pixbuf = gdk_pixbuf_new_from_file (npw_header_get_iconfile (header), NULL);
343 gtk_list_store_set (store, &iter, PIXBUF_COLUMN, pixbuf,
344 TEXT_COLUMN, npw_header_get_name (header),
345 DESC_COLUMN, npw_header_get_description (header),
346 DATA_COLUMN, header,
347 -1);
349 g_object_unref (pixbuf);
352 /* Add a page in the project notebook */
353 static void
354 cb_druid_insert_project_page (gpointer value, gpointer user_data)
356 NPWDruid* druid = (NPWDruid*)user_data;
357 GtkBuilder *builder;
358 GtkWidget* label;
359 GtkWidget* child;
360 GtkWidget* assistant;
361 GtkIconView* view;
362 GtkNotebook *book;
363 GtkListStore *store;
364 GList *template_list = (GList *)value;
365 const gchar* category;
367 category = npw_header_get_category ((NPWHeader *)template_list->data);
369 /* Build another complete wizard dialog from the gtk builder file
370 * but keep only the project selection notebook page */
371 builder = gtk_builder_new ();
372 if (!gtk_builder_add_from_file (builder, GTK_BUILDER_UI_FILE, NULL))
374 g_warn_if_reached ();
375 g_object_unref (builder);
376 return;
379 /* Fill icon view */
380 view = GTK_ICON_VIEW (gtk_builder_get_object (builder, PROJECT_LIST));
381 gtk_icon_view_set_pixbuf_column (view, PIXBUF_COLUMN);
382 gtk_icon_view_set_markup_column (view, TEXT_COLUMN);
383 store = gtk_list_store_new (4, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
384 g_list_foreach (template_list, cb_druid_insert_project_icon, store);
385 gtk_icon_view_set_model (view, GTK_TREE_MODEL (store));
387 /* Connect signal to update dialog */
388 g_signal_connect (G_OBJECT (view), "selection-changed", G_CALLBACK (on_druid_project_update_selected), druid);
389 g_signal_connect (G_OBJECT (view), "map", G_CALLBACK (on_druid_project_update_selected), druid);
390 g_signal_connect_swapped (G_OBJECT (view), "item-activated", G_CALLBACK (gtk_assistant_next_page), druid->window);
392 /* Set new page label */
393 assistant = GTK_WIDGET (gtk_builder_get_object (builder, NEW_PROJECT_DIALOG));
394 book = GTK_NOTEBOOK (gtk_builder_get_object (builder, PROJECT_BOOK));
395 child = gtk_notebook_get_nth_page (book, 0);
396 label = gtk_notebook_get_tab_label (book, child);
397 gtk_label_set_text (GTK_LABEL(label), (const gchar *)category);
399 /* Pick up the filled project selection page from the newly created dialog
400 * add it to the wizard project notebook and destroy the dialog
402 gtk_notebook_remove_page (book, 0);
403 gtk_notebook_append_page (druid->project_book, child, label);
404 gtk_widget_destroy (assistant);
406 g_object_unref (builder);
409 /* Fill project selection page */
410 static gboolean
411 npw_druid_fill_selection_page (NPWDruid* druid, GFile *templates)
413 gchar* dir;
414 const gchar * const * sys_dir;
416 /* Remove all previous data */
417 gtk_notebook_remove_page(druid->project_book, 0);
418 npw_header_list_free (druid->header_list);
419 anjuta_autogen_clear_library_path (druid->gen);
421 /* Create list of projects */
422 druid->header_list = npw_header_list_new ();
424 if (templates != NULL)
426 if (g_file_query_file_type (templates, 0, NULL) == G_FILE_TYPE_DIRECTORY)
428 /* Read project template only in specified directory,
429 * other directories can still be used to get included
430 * files */
431 gchar *directory = g_file_get_path (templates);
433 npw_header_list_readdir (&druid->header_list, directory);
434 anjuta_autogen_set_library_path (druid->gen, directory);
435 g_free (directory);
437 else
439 /* templates is a file, so read only it as a project template */
440 gchar *filename = g_file_get_path (templates);
441 npw_header_list_read (&druid->header_list, filename);
442 g_free (filename);
446 dir = g_build_filename (g_get_user_data_dir (), "anjuta", "templates", NULL);
447 if (templates == NULL)
449 /* Read project template in user directory,
450 * normally ~/.local/share/anjuta/templates,
451 * the first template read override the others */
452 npw_header_list_readdir (&druid->header_list, dir);
454 anjuta_autogen_set_library_path (druid->gen, dir);
455 g_free (dir);
457 for (sys_dir = g_get_system_data_dirs (); *sys_dir != NULL; sys_dir++)
459 dir = g_build_filename (*sys_dir, "anjuta", "templates", NULL);
460 if (templates == NULL)
462 /* Read project template in system directory */
463 npw_header_list_readdir (&druid->header_list, dir);
465 anjuta_autogen_set_library_path (druid->gen, dir);
466 g_free (dir);
469 if (templates == NULL)
471 /* Read anjuta installation directory */
472 npw_header_list_readdir (&druid->header_list, PROJECT_WIZARD_DIRECTORY);
474 anjuta_autogen_set_library_path (druid->gen, PROJECT_WIZARD_DIRECTORY);
476 switch (g_list_length (druid->header_list))
478 case 0:
479 anjuta_util_dialog_error (GTK_WINDOW (ANJUTA_PLUGIN (druid->plugin)->shell),_("Unable to find any project template in %s"), PROJECT_WIZARD_DIRECTORY);
480 return FALSE;
481 case 1:
482 druid->header = (NPWHeader *)((GList *)druid->header_list->data)->data;
483 druid->no_selection = TRUE;
484 gtk_container_remove (GTK_CONTAINER (druid->window), druid->project_page);
485 gtk_assistant_insert_page (GTK_ASSISTANT (druid->window), druid->progress_page, 0);
486 npw_druid_set_busy (druid, FALSE);
487 break;
488 default:
489 /* Add all necessary notebook page */
490 druid->no_selection = FALSE;
491 g_list_foreach (druid->header_list, cb_druid_insert_project_page, druid);
492 gtk_widget_show_all (GTK_WIDGET (druid->project_book));
495 return TRUE;
498 /* Create properties pages
499 *---------------------------------------------------------------------------*/
501 /* Group infomation need by the following call back function */
502 typedef struct _NPWDruidAddPropertyData
504 NPWDruid* druid;
505 guint row;
506 GtkGrid *table;
507 GtkWidget *first_entry;
508 } NPWDruidAddPropertyData;
510 static void
511 cb_druid_destroy_widget (GtkWidget* widget, gpointer user_data)
513 gtk_widget_destroy (widget);
516 static void
517 cb_druid_add_property (NPWProperty* property, gpointer user_data)
519 GtkWidget* label;
520 GtkWidget* entry;
521 NPWDruidAddPropertyData* data = (NPWDruidAddPropertyData *)user_data;
522 const gchar* description;
525 entry = npw_property_create_widget (property);
526 if (entry != NULL)
528 /* Not hidden property */
529 description = npw_property_get_description (property);
531 /* Set description tooltip */
532 if (description && (*description != '\0'))
534 gtk_widget_set_tooltip_text (entry, description);
537 label = gtk_label_new (npw_property_get_label (property));
538 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
539 gtk_misc_set_padding (GTK_MISC (label), 6, 6);
541 gtk_widget_set_hexpand (entry, TRUE);
542 switch (npw_property_get_type (property))
544 case NPW_PACKAGE_PROPERTY:
545 gtk_widget_set_vexpand (entry, TRUE);
546 gtk_grid_attach (data->table, label, 0, data->row, 1, 1);
547 gtk_grid_attach (data->table, entry, 0, data->row + 1, 1, 1);
548 data->row += 2;
549 break;
550 case NPW_BOOLEAN_PROPERTY:
551 gtk_widget_set_hexpand (entry, FALSE);
552 /* Fall through */
553 default:
554 /* Add label and entry */
555 gtk_grid_attach (data->table, label, 0, data->row, 1, 1);
556 gtk_grid_attach (data->table, entry, 1, data->row, 1, 1);
557 data->row++;
560 /* Set first entry */
561 if (data->first_entry == NULL) data->first_entry = entry;
565 static void
566 npw_druid_fill_property_page (NPWDruid* druid, NPWPage* page)
568 GtkWidget *widget;
569 GList *children;
570 GtkLabel *label;
571 NPWDruidAddPropertyData data;
573 /* Add page to assistant, after current page */
574 widget = gtk_assistant_get_nth_page (GTK_ASSISTANT (druid->window), gtk_assistant_get_current_page (GTK_ASSISTANT (druid->window)) + 1);
576 /* Remove previous widgets */
577 gtk_container_foreach (GTK_CONTAINER (npw_page_get_widget (page)), cb_druid_destroy_widget, NULL);
579 /* Update title */
580 children = gtk_container_get_children (GTK_CONTAINER (widget));
581 label = GTK_LABEL (g_list_nth_data (children, 0));
582 g_list_free (children);
583 gtk_label_set_text (label, npw_page_get_label (page));
584 gtk_assistant_set_page_title (GTK_ASSISTANT (druid->window), widget, npw_page_get_label (page));
586 /* Add new widget */
587 data.druid = druid;
588 data.row = 0;
589 data.table = GTK_GRID (npw_page_get_widget (page));
590 data.first_entry = NULL;
591 npw_page_foreach_property (page, (GFunc)cb_druid_add_property, &data);
593 /* Move focus on first entry */
594 if (data.first_entry != NULL)
596 gtk_container_set_focus_child (GTK_CONTAINER (data.table), data.first_entry);
599 gtk_widget_show_all (widget);
602 /* Handle page cache
603 *---------------------------------------------------------------------------*/
605 static NPWPage*
606 npw_druid_add_new_page (NPWDruid* druid)
608 gint current;
609 NPWPage* page;
611 /* Get page in cache */
612 current = gtk_assistant_get_current_page (GTK_ASSISTANT (druid->window));
613 page = g_queue_peek_nth (druid->page_list, current - (druid->no_selection ? 0 : 1) + 1);
615 if (page == NULL)
617 /* Page not found in cache, create */
618 GtkBuilder *builder;
619 GtkWidget *widget;
620 GtkAssistantPageType type;
621 GtkWidget *table;
622 GtkAssistant *assistant;
624 /* Build another complete wizard dialog from the gtk builder file
625 * but keep only the property assistant page */
626 builder = gtk_builder_new ();
627 if (!gtk_builder_add_from_file (builder, GTK_BUILDER_UI_FILE, NULL))
629 g_warn_if_reached ();
630 g_object_unref (builder);
632 return NULL;
634 assistant = GTK_ASSISTANT (gtk_builder_get_object (builder, NEW_PROJECT_DIALOG));
635 widget = GTK_WIDGET (gtk_builder_get_object (builder, PROPERTY_PAGE));
636 table = GTK_WIDGET (gtk_builder_get_object (builder, PROPERTY_TABLE));
638 type = gtk_assistant_get_page_type (assistant, widget);
639 gtk_container_remove (GTK_CONTAINER (assistant), widget);
640 gtk_assistant_insert_page (GTK_ASSISTANT (druid->window), widget, current + 1);
641 gtk_assistant_set_page_type (GTK_ASSISTANT (druid->window), widget, type);
642 gtk_assistant_set_page_complete (GTK_ASSISTANT (druid->window), widget, TRUE);
643 gtk_widget_destroy (GTK_WIDGET (assistant));
645 /* Builder get reference on all built widget, so unref it when all work is done */
646 g_object_unref (builder);
648 /* Create new page */
649 page = npw_page_new (druid->values);
650 npw_page_set_widget (page, table);
652 /* Add page in cache */
653 g_queue_push_tail (druid->page_list, page);
656 return page;
659 /* Remove all pages following current page except the summary page*/
661 static void
662 npw_druid_remove_following_page (NPWDruid* druid)
664 gint current;
666 current = gtk_assistant_get_current_page (GTK_ASSISTANT (druid->window));
667 for(;;)
669 GtkWidget *widget;
670 NPWPage* page;
672 widget = gtk_assistant_get_nth_page (GTK_ASSISTANT (druid->window), current + 1);
673 if (widget == druid->finish_page) break;
675 gtk_container_remove (GTK_CONTAINER (druid->window), widget);
677 page = g_queue_pop_nth (druid->page_list, current - (druid->no_selection ? 0 : 1));
678 if (page != NULL) npw_page_free (page);
682 /* Save properties
683 *---------------------------------------------------------------------------*/
685 typedef struct _NPWSaveValidPropertyData
687 GtkWindow *parent;
688 gboolean modified;
689 GString *error;
690 GString *warning;
692 } NPWSaveValidPropertyData;
694 static void
695 cb_save_valid_property (NPWProperty* property, gpointer user_data)
697 NPWSaveValidPropertyData* data = (NPWSaveValidPropertyData *)user_data;
698 const gchar* value;
699 gboolean modified;
701 /* Get value from widget */
702 modified = npw_property_update_value_from_widget (property);
703 if (modified) data->modified = modified;
704 value = npw_property_get_value (property);
706 /* Check mandatory property */
707 if (modified && (npw_property_get_options (property) & NPW_MANDATORY_OPTION))
709 if ((value == NULL) || (strlen (value) <= 0))
711 g_string_append_printf (data->error,
712 _("\nField \"%s\" is mandatory. Please enter it."),
713 npw_property_get_label (property));
714 npw_property_remove_value (property);
718 /* Check restricted property */
719 if (modified && !npw_property_is_valid_restriction (property))
721 NPWPropertyRestriction restriction = npw_property_get_restriction (property);
723 switch (restriction)
725 case NPW_FILENAME_RESTRICTION:
726 g_string_append_printf (data->error,
727 _("Field \"%s\" must contains only letters, digits or the following characters \"#$:%%+,.=@^_`~\". In addition you cannot have a leading dash. Please fix it."),
728 npw_property_get_label (property));
729 break;
730 case NPW_DIRECTORY_RESTRICTION:
731 g_string_append_printf (data->error,
732 _("Field \"%s\" must contains only letters, digits, the following characters \"#$:%%+,.=@^_`~\" or directory separators. In addition you cannot have a leading dash. Please fix it."),
733 npw_property_get_label (property));
734 break;
735 case NPW_PRINTABLE_RESTRICTION:
736 g_string_append_printf (data->error,
737 _("Field \"%s\" must contains only ASCII printable characters, no accentuated characters by example. Please fix it."),
738 npw_property_get_label (property));
739 break;
740 default:
741 g_string_append_printf (data->error,
742 _("Unknown error."));
745 npw_property_remove_value (property);
748 /* Check exist property */
749 if (modified && (npw_property_get_exist_option (property) == NPW_FALSE))
751 gboolean is_directory = npw_property_get_type (property) == NPW_DIRECTORY_PROPERTY;
752 gboolean exist = (value != NULL) && g_file_test (value, G_FILE_TEST_EXISTS);
753 /* Allow empty directory */
754 if (exist && is_directory)
756 GDir* dir;
758 dir = g_dir_open (value, 0, NULL);
759 if (dir != NULL)
761 if (g_dir_read_name (dir) == NULL) exist = FALSE;
762 g_dir_close (dir);
766 if (exist)
768 g_string_append_printf (data->warning, is_directory ?
769 _("Directory \"%s\" is not empty. Project creation could fail if some files "
770 "cannot be written. Do you want to continue?") :
771 _("File \"%s\" already exists. Do you want to overwrite it?"),
772 value);
777 /* Save values and check them, return TRUE if it's possible to go to
778 * next page */
780 static gboolean
781 npw_druid_save_valid_values (NPWDruid* druid)
783 gint current;
784 NPWPage* page;
785 NPWSaveValidPropertyData data;
786 gboolean ok = TRUE;
788 current = gtk_assistant_get_current_page (GTK_ASSISTANT (druid->window)) - (druid->no_selection ? 0 : 1) - 1;
789 page = g_queue_peek_nth (druid->page_list, current);
790 data.modified = FALSE;
791 data.parent = GTK_WINDOW (druid->window);
792 data.error = g_string_new (NULL);
793 data.warning = g_string_new (NULL);
794 npw_page_foreach_property (page, (GFunc)cb_save_valid_property, &data);
796 if (data.modified) npw_druid_remove_following_page (druid);
798 if (data.error->len)
800 npw_druid_fill_error_page (druid, NULL,
801 GTK_MESSAGE_ERROR,
802 NULL,
803 "<b>%s</b>\n\n%s",
804 _("Invalid entry"),
805 data.error->str);
806 ok = FALSE;
808 else if (data.warning->len)
810 npw_druid_fill_error_page (druid, NULL,
811 GTK_MESSAGE_WARNING,
812 NULL,
813 "<b>%s</b>\n\n%s",
814 _("Dubious entry"),
815 data.warning->str);
816 ok = FALSE;
819 g_string_free (data.error, TRUE);
820 g_string_free (data.warning, TRUE);
822 return ok;
825 /* Druid call backs
826 *---------------------------------------------------------------------------*/
828 static void
829 on_druid_cancel (GtkAssistant* window, NPWDruid* druid)
831 anjuta_plugin_deactivate (ANJUTA_PLUGIN (druid->plugin));
832 npw_druid_free (druid);
835 static void
836 on_druid_close (GtkAssistant* window, NPWDruid* druid)
838 anjuta_plugin_deactivate (ANJUTA_PLUGIN (druid->plugin));
839 npw_druid_free (druid);
842 static gboolean
843 on_project_wizard_key_press_event(GtkWidget *widget, GdkEventKey *event,
844 NPWDruid* druid)
846 if (event->keyval == GDK_KEY_Escape)
848 on_druid_cancel (GTK_ASSISTANT (widget), druid);
849 return TRUE;
851 return FALSE;
854 static void
855 on_druid_get_new_page (AnjutaAutogen* gen, gpointer data)
857 NPWDruid* druid = (NPWDruid *)data;
858 gint current;
859 NPWPage* page;
861 current = gtk_assistant_get_current_page (GTK_ASSISTANT (druid->window));
862 page = g_queue_peek_nth (druid->page_list, current - (druid->no_selection ? 0 : 1));
864 if (npw_page_get_name (page) == NULL)
866 /* no page, display finish page */
867 npw_druid_fill_summary_page (druid);
869 page = g_queue_pop_nth (druid->page_list, current - (druid->no_selection ? 0 : 1));
870 if (page != NULL) npw_page_free (page);
871 gtk_container_remove (GTK_CONTAINER (druid->window), gtk_assistant_get_nth_page (GTK_ASSISTANT (druid->window), current + 1));
872 gtk_assistant_set_current_page (GTK_ASSISTANT (druid->window), current + 1);
874 else
876 /* display property page */
877 npw_druid_fill_property_page (druid, page);
879 gtk_assistant_set_current_page (GTK_ASSISTANT (druid->window), current + 1);
883 static void
884 on_druid_parse_page (const gchar* output, gpointer data)
886 GError *error = NULL;
887 NPWPageParser* parser = (NPWPageParser*)data;
889 npw_page_parser_parse (parser, output, strlen (output), &error);
891 if (error)
893 g_warning ("Parser error: %s", error->message);
894 g_error_free (error);
898 static void
899 strip_package_version_info (gpointer data, gpointer user_data)
901 gchar * const pkg = (gchar *) data;
903 if (!data)
904 return;
905 g_strdelimit (pkg, " ", '\0');
908 static void
909 on_install_button_clicked (GtkWidget *button, NPWDruid *druid)
911 GList *missing_programs, *missing_packages;
912 GList *missing_files = NULL;
913 GList *node;
916 missing_programs = npw_header_check_required_programs (druid->header);
917 missing_packages = npw_header_check_required_packages (druid->header);
919 anjuta_util_glist_strings_prefix (missing_programs, "/usr/bin/");
921 /* Search for "pkgconfig(pkg_name)" */
922 g_list_foreach (missing_packages, (GFunc) strip_package_version_info,
923 NULL);
924 missing_files = g_list_concat (missing_files, missing_programs);
926 for (node = missing_packages; node != NULL; node = g_list_next (missing_packages))
928 gchar* pk_pkg_config_string = g_strdup_printf ("pkgconfig(%s)", (gchar*) node->data);
929 missing_files = g_list_append (missing_files, pk_pkg_config_string);
931 g_list_free (missing_packages);
933 if (missing_files)
935 gchar * missing_names = NULL;
937 missing_names = anjuta_util_glist_strings_join (missing_files, ", ");
938 anjuta_util_install_files (missing_names);
940 if (missing_names)
941 g_free (missing_names);
942 anjuta_util_glist_strings_free (missing_files);
946 static gboolean
947 check_and_warn_missing (NPWDruid *druid)
949 GList *missing_programs, *missing_packages;
950 GString *missing_message = NULL;
952 missing_programs = npw_header_check_required_programs (druid->header);
953 missing_packages = npw_header_check_required_packages (druid->header);
955 if (missing_programs || missing_packages)
957 missing_message = g_string_new (NULL);
960 if (missing_programs)
962 gchar *missing_progs;
963 missing_progs = anjuta_util_glist_strings_join (missing_programs,
964 ", ");
965 g_string_append_printf (missing_message,
966 _("\nMissing programs: %s."), missing_progs);
967 g_free (missing_progs);
968 anjuta_util_glist_strings_free (missing_programs);
971 if (missing_packages)
973 gchar *missing_pkgs;
974 missing_pkgs = anjuta_util_glist_strings_join (missing_packages,
975 ", ");
976 g_string_append_printf (missing_message,
977 _("\nMissing packages: %s."), missing_pkgs);
978 g_free (missing_pkgs);
979 anjuta_util_glist_strings_free (missing_packages);
982 if (missing_message)
984 GtkWidget *hbox, *install_button;
985 g_string_prepend (missing_message, _(
986 "Some important programs or development packages required to build "
987 "this project are missing. Please make sure they are "
988 "installed properly before generating the project.\n"));
990 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
991 gtk_widget_show (hbox);
993 #ifdef ENABLE_PACKAGEKIT
994 install_button =
995 gtk_button_new_with_label (_("Install missing packages"));
996 gtk_box_pack_end (GTK_BOX (hbox), install_button, FALSE, FALSE, 10);
997 g_signal_connect (install_button, "clicked",
998 G_CALLBACK (on_install_button_clicked), druid);
999 gtk_widget_show (install_button);
1000 #endif
1002 npw_druid_fill_error_page (druid, hbox,
1003 GTK_MESSAGE_WARNING,
1004 /* Translators: Application Manager is the program used to install
1005 * new application like apt on Ubuntu, yum on Fedora, zypper on
1006 * OpenSuSE and emerge on Gentoo */
1007 _("The missing programs are usually part of some distribution "
1008 "packages and can be searched for in your Application Manager. "
1009 "Similarly, the development packages are contained in special "
1010 "packages that your distribution provides to allow development "
1011 "of projects based on them. They usually end with a \"-dev\" or "
1012 "\"-devel\" suffix in package names and can be found by searching "
1013 "in your Application Manager."),
1014 "<b>%s</b>\n\n%s",
1015 _("Missing components"),
1016 missing_message->str);
1017 g_string_free (missing_message, TRUE);
1020 return !missing_message;
1024 static void
1025 on_druid_real_prepare (GtkAssistant* assistant, GtkWidget *page, NPWDruid* druid)
1027 if (page == druid->progress_page)
1029 gint previous;
1030 gboolean last_warning;
1032 previous = gtk_assistant_get_current_page (assistant) - 1;
1033 last_warning = gtk_assistant_get_nth_page (assistant, previous) == druid->error_page;
1034 if (last_warning)
1036 /* Remove warning page */
1037 gtk_container_remove (GTK_CONTAINER (assistant), druid->error_page);
1038 previous--;
1040 if (druid->no_selection) previous++;
1042 /* Generate the next page */
1043 if (previous == PROJECT_PAGE_INDEX)
1045 const gchar* new_project;
1047 new_project = npw_header_get_filename (druid->header);
1049 if (druid->project_file != new_project)
1051 npw_druid_remove_following_page (druid);
1053 /* Check if necessary programs for this project is installed */
1054 if (!last_warning && !check_and_warn_missing (druid))
1056 gtk_assistant_set_current_page (assistant, gtk_assistant_get_current_page (assistant) + 1);
1057 return;
1060 /* Change project */
1061 druid->project_file = new_project;
1062 anjuta_autogen_set_input_file (druid->gen, druid->project_file, "[+","+]");
1066 else
1068 if (!npw_druid_save_valid_values (druid))
1070 /* Display error */
1071 gtk_assistant_set_current_page (assistant, gtk_assistant_get_current_page (assistant) + 1);
1073 return;
1077 if (g_queue_peek_nth (druid->page_list, previous) == NULL)
1079 /* Regenerate new page */
1080 gtk_assistant_set_page_complete (assistant, page, FALSE);
1081 if (druid->parser != NULL)
1082 npw_page_parser_free (druid->parser);
1083 druid->parser = npw_page_parser_new (npw_druid_add_new_page (druid), druid->project_file, previous);
1085 anjuta_autogen_set_output_callback (druid->gen, on_druid_parse_page, druid->parser, NULL);
1086 anjuta_autogen_write_definition_file (druid->gen, druid->values, NULL);
1087 anjuta_autogen_execute (druid->gen, on_druid_get_new_page, druid, NULL);
1089 else
1091 /* Page is already in cache, change the page to display it */
1092 on_druid_get_new_page (NULL, druid);
1095 else if (page == druid->finish_page)
1097 npw_druid_set_busy (druid, FALSE);
1098 gtk_container_remove (GTK_CONTAINER (assistant), druid->error_page);
1099 gtk_container_remove (GTK_CONTAINER (assistant), druid->progress_page);
1101 else
1103 npw_druid_set_busy (druid, FALSE);
1105 if (page != druid->error_page) gtk_container_remove (GTK_CONTAINER (assistant), druid->error_page);
1107 /* Move progress page */
1108 gtk_container_remove (GTK_CONTAINER (assistant), druid->progress_page);
1109 gtk_assistant_insert_page (assistant, druid->progress_page, gtk_assistant_get_current_page (assistant) + 1);
1110 gtk_assistant_set_page_title (assistant, druid->progress_page, "...");
1114 static gboolean
1115 on_druid_delayed_prepare (gpointer data)
1117 NPWDruid *druid = (NPWDruid *)data;
1118 GtkAssistant *assistant;
1119 GtkWidget *page;
1121 assistant = GTK_ASSISTANT (druid->window);
1122 page = gtk_assistant_get_nth_page (assistant, gtk_assistant_get_current_page (assistant));
1123 on_druid_real_prepare (assistant, page, druid);
1125 return FALSE;
1128 static void
1129 on_druid_prepare (GtkAssistant* assistant, GtkWidget *page, NPWDruid* druid)
1131 /* The page change is delayed because in the latest version of
1132 * GtkAssistant, the page switch is not completely done when
1133 * the signal is called. A page change in the signal handler
1134 * will be partialy overwritten */
1135 g_idle_add (on_druid_delayed_prepare, druid);
1138 static void
1139 npw_druid_save_default_property (NPWDruid* druid)
1141 GSettings *settings;
1142 const gchar *new_value;
1143 gchar *old_value;
1146 settings = g_settings_new (ANJUTA_PREF_SCHEMA_PREFIX PROJECT_WIZARD_PREF_SCHEMA);
1148 new_value = g_hash_table_lookup (druid->values, DESTINATION_PROPERTY);
1149 if ((new_value != NULL) && (*new_value != '\0'))
1151 /* Remove project directory */
1152 gchar *parent;
1154 parent = g_path_get_dirname (new_value);
1155 if (new_value[strlen(new_value) - 1] == G_DIR_SEPARATOR)
1157 gchar *dir = parent;
1158 parent = g_path_get_dirname (dir);
1159 g_free (dir);
1162 old_value = g_settings_get_string (settings, LAST_DIRECTORY);
1163 if (strcmp (parent, old_value) != 0)
1165 /* If the new directory is in the home directory, store a relative
1166 * path */
1167 const gchar *home;
1168 size_t len;
1170 home = g_get_home_dir ();
1171 len = strlen (home);
1172 if ((strncmp (home, parent, len) == 0) && ((parent[len] == G_DIR_SEPARATOR) || (parent[len] == '\0')))
1174 g_settings_set_string (settings, LAST_DIRECTORY, parent[len] == '\0' ? "" : parent + len + 1);
1176 else
1178 g_settings_set_string (settings, LAST_DIRECTORY, parent);
1181 g_free (old_value);
1182 g_free (parent);
1185 new_value = g_hash_table_lookup (druid->values, AUTHOR_PROPERTY);
1186 if ((new_value != NULL) && (*new_value != '\0'))
1188 old_value = g_settings_get_string (settings, LAST_USER_NAME);
1189 if (strcmp (new_value, old_value) != 0)
1191 g_settings_set_string (settings, LAST_USER_NAME, new_value);
1193 g_free (old_value);
1196 new_value = g_hash_table_lookup (druid->values, EMAIL_PROPERTY);
1197 if ((new_value != NULL) && (*new_value != '\0'))
1199 old_value = g_settings_get_string (settings, LAST_EMAIL);
1200 if (strcmp (new_value, old_value) != 0)
1202 g_settings_set_string (settings, LAST_EMAIL, new_value);
1204 g_free (old_value);
1208 static void
1209 on_druid_finish (GtkAssistant* assistant, NPWDruid* druid)
1211 NPWInstall* inst;
1212 GList *path;
1214 npw_druid_save_default_property (druid);
1216 inst = npw_install_new (druid->plugin);
1217 npw_install_set_property (inst, druid->values);
1218 npw_install_set_wizard_file (inst, npw_header_get_filename (druid->header));
1219 for (path = g_list_last (anjuta_autogen_get_library_paths (druid->gen)); path != NULL; path = g_list_previous (path))
1221 npw_install_set_library_path (inst, (const gchar *)path->data);
1223 npw_install_launch (inst);
1226 static GtkWidget*
1227 npw_druid_create_assistant (NPWDruid* druid, GFile *templates)
1229 AnjutaShell *shell;
1230 GtkBuilder *builder;
1231 GError* error = NULL;
1232 GtkAssistant *assistant;
1233 GtkWidget *property_page;
1235 g_return_val_if_fail (druid->window == NULL, NULL);
1237 shell = ANJUTA_PLUGIN (druid->plugin)->shell;
1239 /* Create GtkAssistant using GtkBuilder, glade doesn't seem to work*/
1240 builder = gtk_builder_new ();
1241 if (!gtk_builder_add_from_file (builder, GTK_BUILDER_UI_FILE, &error))
1243 g_warning ("Couldn't load builder file: %s", error->message);
1244 g_error_free (error);
1245 return NULL;
1247 anjuta_util_builder_get_objects (builder,
1248 NEW_PROJECT_DIALOG, &assistant,
1249 PROJECT_BOOK, &druid->project_book,
1250 ERROR_VBOX, &druid->error_vbox,
1251 ERROR_TITLE, &druid->error_title,
1252 ERROR_ICON, &druid->error_icon,
1253 ERROR_MESSAGE, &druid->error_message,
1254 ERROR_DETAIL, &druid->error_detail,
1255 PROJECT_PAGE, &druid->project_page,
1256 ERROR_PAGE, &druid->error_page,
1257 PROGRESS_PAGE, &druid->progress_page,
1258 FINISH_PAGE, &druid->finish_page,
1259 FINISH_TEXT, &druid->finish_text,
1260 PROPERTY_PAGE, &property_page,
1261 NULL);
1262 druid->window = GTK_WINDOW (assistant);
1263 gtk_window_set_transient_for (GTK_WINDOW (assistant), GTK_WINDOW (shell));
1264 g_object_unref (builder);
1266 /* Connect assistant signals */
1267 g_signal_connect (G_OBJECT (assistant), "prepare", G_CALLBACK (on_druid_prepare), druid);
1268 g_signal_connect (G_OBJECT (assistant), "apply", G_CALLBACK (on_druid_finish), druid);
1269 g_signal_connect (G_OBJECT (assistant), "cancel", G_CALLBACK (on_druid_cancel), druid);
1270 g_signal_connect (G_OBJECT (assistant), "close", G_CALLBACK (on_druid_close), druid);
1271 g_signal_connect(G_OBJECT(assistant), "key-press-event", G_CALLBACK(on_project_wizard_key_press_event), druid);
1273 /* Remove property page, will be created later as needed */
1274 gtk_container_remove (GTK_CONTAINER (assistant), property_page);
1275 /* Remove error page, could be needed later so keep a ref */
1276 g_object_ref (druid->error_page);
1277 gtk_container_remove (GTK_CONTAINER (assistant), druid->error_page);
1278 /* Remove progress page, could be needed later so keep a ref */
1279 g_object_ref (druid->progress_page);
1280 gtk_container_remove (GTK_CONTAINER (assistant), druid->progress_page);
1282 /* Setup project selection page */
1283 if (!npw_druid_fill_selection_page (druid, templates))
1285 return NULL;
1288 /* Add dialog widget to anjuta status. */
1289 anjuta_status_add_widget (anjuta_shell_get_status (shell, NULL), GTK_WIDGET (assistant));
1291 gtk_window_set_default_size (GTK_WINDOW (assistant),
1292 600, 500);
1294 gtk_widget_show_all (GTK_WIDGET (assistant));
1296 return GTK_WIDGET(assistant);
1299 /* Add default property
1300 *---------------------------------------------------------------------------*/
1302 static void
1303 npw_druid_add_default_property (NPWDruid* druid)
1305 gchar* s;
1306 GSettings *settings;
1307 gboolean flag;
1308 gint i;
1311 /* Add default base project directory */
1312 settings = g_settings_new (ANJUTA_PREF_SCHEMA_PREFIX PROJECT_WIZARD_PREF_SCHEMA);
1313 s = g_settings_get_string (settings,LAST_DIRECTORY);
1314 if (*s == '\0')
1316 s = g_strdup (g_get_home_dir());
1318 else if (!g_path_is_absolute (s))
1320 gchar *path;
1322 path = g_build_filename (g_get_home_dir(), s, NULL);
1323 g_free (s);
1324 s = path;
1326 g_hash_table_insert (druid->values, g_strdup (ANJUTA_PROJECT_DIRECTORY_PROPERTY), s);
1328 /* Add user name */
1329 s = g_settings_get_string (settings,LAST_USER_NAME);
1330 if (*s == '\0')
1332 g_free (s);
1333 s = g_strdup (g_get_real_name());
1335 g_hash_table_insert (druid->values, g_strdup (USER_NAME_PROPERTY), s);
1337 /* Add Email address */
1338 s = g_settings_get_string (settings,LAST_EMAIL);
1339 if (*s == '\0')
1341 g_free (s);
1342 s = anjuta_util_get_user_mail();
1344 g_hash_table_insert (druid->values, g_strdup (EMAIL_ADDRESS_PROPERTY), s);
1345 g_object_unref (settings);
1347 /* Add use-tabs property */
1348 settings = g_settings_new (ANJUTA_PREF_SCHEMA_PREFIX IANJUTA_EDITOR_PREF_SCHEMA);
1349 flag = g_settings_get_boolean (settings, IANJUTA_EDITOR_USE_TABS_KEY);
1350 g_hash_table_insert (druid->values, g_strdup (USE_TABS_PROPERTY), g_strdup (flag ? "1" : "0"));
1352 /* Add tab-width property */
1353 i = g_settings_get_int (settings, IANJUTA_EDITOR_TAB_WIDTH_KEY);
1354 g_hash_table_insert (druid->values, g_strdup (TAB_WIDTH_PROPERTY), g_strdup_printf("%d", i));
1356 /* Add indent-width property */
1357 i = g_settings_get_int (settings, IANJUTA_EDITOR_INDENT_WIDTH_KEY);
1358 g_hash_table_insert (druid->values, g_strdup (INDENT_WIDTH_PROPERTY), g_strdup_printf("%d", i));
1359 g_object_unref (settings);
1362 /* Druid public functions
1363 *---------------------------------------------------------------------------*/
1365 NPWDruid*
1366 npw_druid_new (NPWPlugin* plugin, GFile *templates)
1368 NPWDruid* druid;
1370 /* Check if autogen is present */
1371 if (!anjuta_check_autogen())
1373 anjuta_util_dialog_error (NULL, _("Could not find autogen version 5; please install the autogen package. You can get it from http://autogen.sourceforge.net."));
1374 return NULL;
1377 druid = g_new0(NPWDruid, 1);
1378 druid->plugin = plugin;
1379 druid->project_file = NULL;
1380 druid->busy = FALSE;
1381 druid->no_selection = FALSE;
1382 druid->page_list = g_queue_new ();
1383 druid->values = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_free);
1384 druid->gen = anjuta_autogen_new ();
1385 plugin->druid = druid;
1386 druid->error_extra_widget = NULL;
1388 if (npw_druid_create_assistant (druid, templates) == NULL)
1390 npw_druid_free (druid);
1392 return NULL;
1395 npw_druid_add_default_property (druid);
1397 return druid;
1400 void
1401 npw_druid_free (NPWDruid* druid)
1403 NPWPage* page;
1405 g_return_if_fail (druid != NULL);
1407 /* Delete page list */
1409 while ((page = (NPWPage *)g_queue_pop_head (druid->page_list)) != NULL)
1411 npw_page_free (page);
1413 g_queue_free (druid->page_list);
1414 g_hash_table_destroy (druid->values);
1415 g_object_unref (G_OBJECT (druid->gen));
1416 if (druid->parser != NULL) npw_page_parser_free (druid->parser);
1417 npw_header_list_free (druid->header_list);
1418 /* Destroy project notebook first to avoid a critical warning */
1419 gtk_widget_destroy (GTK_WIDGET (druid->project_book));
1420 gtk_widget_destroy (GTK_WIDGET (druid->window));
1421 g_object_unref (druid->error_page);
1422 g_object_unref (druid->progress_page);
1423 druid->plugin->druid = NULL;
1424 g_free (druid);
1427 void
1428 npw_druid_show (NPWDruid* druid)
1430 g_return_if_fail (druid != NULL);
1432 /* Display dialog box */
1433 if (druid->window) gtk_window_present (druid->window);