1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
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
24 *---------------------------------------------------------------------------*/
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>
42 #include <glib/gi18n.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 /*---------------------------------------------------------------------------*/
107 GtkNotebook
* project_book
;
108 GtkWidget
*error_page
;
109 GtkWidget
*error_title
;
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
;
127 NPWPageParser
* parser
;
130 gboolean no_selection
;
135 /* column of the icon view */
144 *---------------------------------------------------------------------------*/
146 /* Druid GUI functions
147 *---------------------------------------------------------------------------*/
150 npw_druid_set_busy (NPWDruid
*druid
, gboolean busy_state
)
152 if (druid
->busy
== busy_state
)
157 anjuta_status_busy_push (anjuta_shell_get_status (ANJUTA_PLUGIN (druid
->plugin
)->shell
, NULL
));
159 anjuta_status_busy_pop (anjuta_shell_get_status (ANJUTA_PLUGIN (druid
->plugin
)->shell
, NULL
));
160 druid
->busy
= busy_state
;
164 *---------------------------------------------------------------------------*/
166 /* Fill dialog page */
168 npw_druid_fill_error_page (NPWDruid
* druid
, GtkWidget
*extra_widget
, GtkMessageType type
, const gchar
*detail
, const gchar
*mesg
,...)
170 GtkAssistant
*assistant
;
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 */
186 case GTK_MESSAGE_INFO
:
187 stock_id
= GTK_STOCK_DIALOG_INFO
;
188 title
= _("Information");
190 case GTK_MESSAGE_QUESTION
:
191 stock_id
= GTK_STOCK_DIALOG_QUESTION
;
192 title
= _("Warning");
194 case GTK_MESSAGE_WARNING
:
195 stock_id
= GTK_STOCK_DIALOG_WARNING
;
196 title
= _("Warning");
198 case GTK_MESSAGE_ERROR
:
199 stock_id
= GTK_STOCK_DIALOG_ERROR
;
202 case GTK_MESSAGE_OTHER
:
203 title
= _("Message");
206 g_warning ("Unknown GtkMessageType %u", type
);
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
);
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
);
224 va_start (args
, mesg
);
225 message
= g_strdup_vprintf (mesg
, args
);
227 gtk_label_set_markup (druid
->error_message
, message
);
233 gtk_widget_hide (druid
->error_detail
);
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 */
251 gtk_box_pack_start (GTK_BOX (druid
->error_vbox
), extra_widget
,
253 gtk_widget_show (extra_widget
);
254 druid
->error_extra_widget
= extra_widget
;
258 /* Create finish page
259 *---------------------------------------------------------------------------*/
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) */
276 npw_druid_fill_summary_page (NPWDruid
* druid
)
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 */
307 on_druid_project_update_selected (GtkIconView
* view
, NPWDruid
*druid
)
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
)
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 */
334 cb_druid_insert_project_icon (gpointer data
, gpointer user_data
)
336 NPWHeader
*header
= (NPWHeader
*)data
;
337 GtkListStore
* store
= GTK_LIST_STORE (user_data
);
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
),
349 g_object_unref (pixbuf
);
352 /* Add a page in the project notebook */
354 cb_druid_insert_project_page (gpointer value
, gpointer user_data
)
356 NPWDruid
* druid
= (NPWDruid
*)user_data
;
360 GtkWidget
* assistant
;
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
);
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 */
411 npw_druid_fill_selection_page (NPWDruid
* druid
, GFile
*templates
)
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
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
);
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
);
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
);
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
);
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
))
479 anjuta_util_dialog_error (GTK_WINDOW (ANJUTA_PLUGIN (druid
->plugin
)->shell
),_("Unable to find any project template in %s"), PROJECT_WIZARD_DIRECTORY
);
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
);
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
));
498 /* Create properties pages
499 *---------------------------------------------------------------------------*/
501 /* Group infomation need by the following call back function */
502 typedef struct _NPWDruidAddPropertyData
507 GtkWidget
*first_entry
;
508 } NPWDruidAddPropertyData
;
511 cb_druid_destroy_widget (GtkWidget
* widget
, gpointer user_data
)
513 gtk_widget_destroy (widget
);
517 cb_druid_add_property (NPWProperty
* property
, gpointer user_data
)
521 NPWDruidAddPropertyData
* data
= (NPWDruidAddPropertyData
*)user_data
;
522 const gchar
* description
;
525 entry
= npw_property_create_widget (property
);
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);
550 case NPW_BOOLEAN_PROPERTY
:
551 gtk_widget_set_hexpand (entry
, FALSE
);
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);
560 /* Set first entry */
561 if (data
->first_entry
== NULL
) data
->first_entry
= entry
;
566 npw_druid_fill_property_page (NPWDruid
* druid
, NPWPage
* page
)
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
);
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
));
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
);
603 *---------------------------------------------------------------------------*/
606 npw_druid_add_new_page (NPWDruid
* druid
)
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);
617 /* Page not found in cache, create */
620 GtkAssistantPageType type
;
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
);
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
);
659 /* Remove all pages following current page except the summary page*/
662 npw_druid_remove_following_page (NPWDruid
* druid
)
666 current
= gtk_assistant_get_current_page (GTK_ASSISTANT (druid
->window
));
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
);
683 *---------------------------------------------------------------------------*/
685 typedef struct _NPWSaveValidPropertyData
692 } NPWSaveValidPropertyData
;
695 cb_save_valid_property (NPWProperty
* property
, gpointer user_data
)
697 NPWSaveValidPropertyData
* data
= (NPWSaveValidPropertyData
*)user_data
;
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
);
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
));
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
));
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
));
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
)
758 dir
= g_dir_open (value
, 0, NULL
);
761 if (g_dir_read_name (dir
) == NULL
) exist
= FALSE
;
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?"),
777 /* Save values and check them, return TRUE if it's possible to go to
781 npw_druid_save_valid_values (NPWDruid
* druid
)
785 NPWSaveValidPropertyData data
;
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
);
800 npw_druid_fill_error_page (druid
, NULL
,
808 else if (data
.warning
->len
)
810 npw_druid_fill_error_page (druid
, NULL
,
819 g_string_free (data
.error
, TRUE
);
820 g_string_free (data
.warning
, TRUE
);
826 *---------------------------------------------------------------------------*/
829 on_druid_cancel (GtkAssistant
* window
, NPWDruid
* druid
)
831 anjuta_plugin_deactivate (ANJUTA_PLUGIN (druid
->plugin
));
832 npw_druid_free (druid
);
836 on_druid_close (GtkAssistant
* window
, NPWDruid
* druid
)
838 anjuta_plugin_deactivate (ANJUTA_PLUGIN (druid
->plugin
));
839 npw_druid_free (druid
);
843 on_project_wizard_key_press_event(GtkWidget
*widget
, GdkEventKey
*event
,
846 if (event
->keyval
== GDK_KEY_Escape
)
848 on_druid_cancel (GTK_ASSISTANT (widget
), druid
);
855 on_druid_get_new_page (AnjutaAutogen
* gen
, gpointer data
)
857 NPWDruid
* druid
= (NPWDruid
*)data
;
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);
876 /* display property page */
877 npw_druid_fill_property_page (druid
, page
);
879 gtk_assistant_set_current_page (GTK_ASSISTANT (druid
->window
), current
+ 1);
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
);
893 g_warning ("Parser error: %s", error
->message
);
894 g_error_free (error
);
899 strip_package_version_info (gpointer data
, gpointer user_data
)
901 gchar
* const pkg
= (gchar
*) data
;
905 g_strdelimit (pkg
, " ", '\0');
909 on_install_button_clicked (GtkWidget
*button
, NPWDruid
*druid
)
911 GList
*missing_programs
, *missing_packages
;
912 GList
*missing_files
= NULL
;
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
,
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
);
935 gchar
* missing_names
= NULL
;
937 missing_names
= anjuta_util_glist_strings_join (missing_files
, ", ");
938 anjuta_util_install_files (missing_names
);
941 g_free (missing_names
);
942 anjuta_util_glist_strings_free (missing_files
);
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
,
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
)
974 missing_pkgs
= anjuta_util_glist_strings_join (missing_packages
,
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
);
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
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
);
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."),
1015 _("Missing components"),
1016 missing_message
->str
);
1017 g_string_free (missing_message
, TRUE
);
1020 return !missing_message
;
1025 on_druid_real_prepare (GtkAssistant
* assistant
, GtkWidget
*page
, NPWDruid
* druid
)
1027 if (page
== druid
->progress_page
)
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
;
1036 /* Remove warning page */
1037 gtk_container_remove (GTK_CONTAINER (assistant
), druid
->error_page
);
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);
1060 /* Change project */
1061 druid
->project_file
= new_project
;
1062 anjuta_autogen_set_input_file (druid
->gen
, druid
->project_file
, "[+","+]");
1068 if (!npw_druid_save_valid_values (druid
))
1071 gtk_assistant_set_current_page (assistant
, gtk_assistant_get_current_page (assistant
) + 1);
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
);
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
);
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
, "...");
1115 on_druid_delayed_prepare (gpointer data
)
1117 NPWDruid
*druid
= (NPWDruid
*)data
;
1118 GtkAssistant
*assistant
;
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
);
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
);
1139 npw_druid_save_default_property (NPWDruid
* druid
)
1141 GSettings
*settings
;
1142 const gchar
*new_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 */
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
);
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
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);
1178 g_settings_set_string (settings
, LAST_DIRECTORY
, 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
);
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
);
1209 on_druid_finish (GtkAssistant
* assistant
, NPWDruid
* druid
)
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
);
1227 npw_druid_create_assistant (NPWDruid
* druid
, GFile
*templates
)
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
);
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
,
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
))
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
),
1294 gtk_widget_show_all (GTK_WIDGET (assistant
));
1296 return GTK_WIDGET(assistant
);
1299 /* Add default property
1300 *---------------------------------------------------------------------------*/
1303 npw_druid_add_default_property (NPWDruid
* druid
)
1306 GSettings
*settings
;
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
);
1316 s
= g_strdup (g_get_home_dir());
1318 else if (!g_path_is_absolute (s
))
1322 path
= g_build_filename (g_get_home_dir(), s
, NULL
);
1326 g_hash_table_insert (druid
->values
, g_strdup (ANJUTA_PROJECT_DIRECTORY_PROPERTY
), s
);
1329 s
= g_settings_get_string (settings
,LAST_USER_NAME
);
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
);
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 *---------------------------------------------------------------------------*/
1366 npw_druid_new (NPWPlugin
* plugin
, GFile
*templates
)
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."));
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
);
1395 npw_druid_add_default_property (druid
);
1401 npw_druid_free (NPWDruid
* druid
)
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
;
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
);