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 "/project"
54 /* Default property name useable in wizard file
55 *---------------------------------------------------------------------------*/
57 #define ANJUTA_PROJECT_DIRECTORY_PROPERTY "AnjutaProjectDirectory"
58 #define USER_NAME_PROPERTY "UserName"
59 #define EMAIL_ADDRESS_PROPERTY "EmailAddress"
60 #define INDENT_WIDTH_PROPERTY "IndentWidth"
61 #define TAB_WIDTH_PROPERTY "TabWidth"
62 #define USE_TABS_PROPERTY "UseTabs"
64 /* Common editor preferences */
65 #define ANJUTA_PREF_SCHEMA_PREFIX "org.gnome.anjuta."
68 /* Widget and signal name found in glade file
69 *---------------------------------------------------------------------------*/
71 #define GTK_BUILDER_UI_FILE PACKAGE_DATA_DIR "/glade/anjuta-project-wizard.ui"
73 #define NEW_PROJECT_DIALOG "druid_window"
74 #define PROJECT_LIST "project_list"
75 #define PROJECT_BOOK "project_book"
76 #define PROJECT_PAGE "project_page"
77 #define ERROR_PAGE "error_page"
78 #define ERROR_TITLE "error_title"
79 #define PROGRESS_PAGE "progress_page"
80 #define FINISH_PAGE "finish_page"
81 #define FINISH_TEXT "finish_text"
82 #define PROPERTY_PAGE "property_page"
83 #define PROPERTY_TITLE "property_title"
84 #define PROPERTY_TABLE "property_table"
85 #define ERROR_VBOX "error_vbox"
86 #define ERROR_ICON "error_icon"
87 #define ERROR_MESSAGE "error_message"
88 #define ERROR_DETAIL "error_detail"
91 #define PROJECT_PAGE_INDEX 0
93 /*---------------------------------------------------------------------------*/
99 GtkNotebook
* project_book
;
100 GtkWidget
*error_page
;
101 GtkWidget
*error_title
;
103 GtkWidget
*error_extra_widget
;
104 GtkImage
*error_icon
;
105 GtkLabel
*error_message
;
106 GtkWidget
*error_detail
;
108 GtkWidget
*project_page
;
109 GtkWidget
*progress_page
;
110 GtkWidget
*finish_page
;
111 GtkWidget
*finish_text
;
113 const gchar
* project_file
;
119 NPWPageParser
* parser
;
126 /* column of the icon view */
135 *---------------------------------------------------------------------------*/
138 *---------------------------------------------------------------------------*/
140 /* Fill dialog page */
142 npw_druid_fill_error_page (NPWDruid
* druid
, GtkWidget
*extra_widget
, GtkMessageType type
, const gchar
*detail
, const gchar
*mesg
,...)
144 GtkAssistant
*assistant
;
148 const gchar
*stock_id
= NULL
;
149 const gchar
*title
= NULL
;
151 assistant
= GTK_ASSISTANT (druid
->window
);
153 /* Add page to assistant after current one */
154 page
= druid
->error_page
;
155 gtk_assistant_insert_page (assistant
, page
, gtk_assistant_get_current_page (assistant
) + 1);
157 /* Set dialog kind */
160 case GTK_MESSAGE_INFO
:
161 stock_id
= GTK_STOCK_DIALOG_INFO
;
162 title
= _("Information");
164 case GTK_MESSAGE_QUESTION
:
165 stock_id
= GTK_STOCK_DIALOG_QUESTION
;
166 title
= _("Warning");
168 case GTK_MESSAGE_WARNING
:
169 stock_id
= GTK_STOCK_DIALOG_WARNING
;
170 title
= _("Warning");
172 case GTK_MESSAGE_ERROR
:
173 stock_id
= GTK_STOCK_DIALOG_ERROR
;
176 case GTK_MESSAGE_OTHER
:
177 title
= _("Message");
180 g_warning ("Unknown GtkMessageType %u", type
);
183 gtk_label_set_text (GTK_LABEL (druid
->error_title
), title
);
184 gtk_assistant_set_page_title (assistant
, page
, title
);
185 if (type
== GTK_MESSAGE_ERROR
)
187 gtk_assistant_set_page_type (assistant
, page
, GTK_ASSISTANT_PAGE_CONTENT
);
188 gtk_assistant_set_page_complete (assistant
, page
, FALSE
);
192 gtk_assistant_set_page_type (assistant
, page
, GTK_ASSISTANT_PAGE_PROGRESS
);
193 gtk_assistant_set_page_complete (assistant
, page
, TRUE
);
195 gtk_image_set_from_stock (druid
->error_icon
, stock_id
, GTK_ICON_SIZE_DIALOG
);
198 va_start (args
, mesg
);
199 message
= g_strdup_vprintf (mesg
, args
);
201 gtk_label_set_markup (druid
->error_message
, message
);
207 gtk_widget_hide (druid
->error_detail
);
213 gtk_widget_show (druid
->error_detail
);
214 label
= GTK_LABEL (gtk_bin_get_child (GTK_BIN (druid
->error_detail
)));
215 gtk_label_set_text (label
, detail
);
218 if (druid
->error_extra_widget
)
219 gtk_widget_destroy (druid
->error_extra_widget
);
220 druid
->error_extra_widget
= NULL
;
222 /* Set extra widget */
225 gtk_box_pack_start (GTK_BOX (druid
->error_vbox
), extra_widget
,
227 gtk_widget_show (extra_widget
);
228 druid
->error_extra_widget
= extra_widget
;
232 /* Create finish page
233 *---------------------------------------------------------------------------*/
236 cb_druid_add_summary_property (NPWProperty
* property
, gpointer user_data
)
238 GString
* text
= (GString
*)user_data
;
240 if (npw_property_get_options (property
) & NPW_SUMMARY_OPTION
)
242 g_string_append_printf (text
, "%s %s\n",
243 npw_property_get_label (property
),
244 npw_property_get_value (property
));
248 /* Fill last page (summary) */
250 npw_druid_fill_summary_page (NPWDruid
* druid
)
257 text
= g_string_new (NULL
);
258 g_string_append_printf (text
, "<b>%s</b>\n\n", _("Confirm the following information:"));
260 /* The project type is translated too, it is something like
261 * generic, GNOME applet, Makefile project... */
262 g_string_append_printf (text
, _("Project Type: %s\n"), npw_header_get_name (druid
->header
));
264 for (i
= 0; (page
= g_queue_peek_nth (druid
->page_list
, i
)) != NULL
; ++i
)
266 npw_page_foreach_property (page
, (GFunc
)cb_druid_add_summary_property
, text
);
269 label
= GTK_LABEL (druid
->finish_text
);
270 gtk_label_set_markup (label
, text
->str
);
271 g_string_free (text
, TRUE
);
273 gtk_assistant_set_page_complete (GTK_ASSISTANT (druid
->window
), druid
->finish_page
, TRUE
);
276 /* Create project selection page
277 *---------------------------------------------------------------------------*/
279 /* Update selected project */
281 on_druid_project_update_selected (GtkIconView
* view
, NPWDruid
*druid
)
284 NPWHeader
* header
= NULL
;
286 /* No item can be selected when the view is mapped */
287 selected
= gtk_icon_view_get_selected_items (view
);
288 if (selected
!= NULL
)
293 model
= gtk_icon_view_get_model (view
);
294 if (gtk_tree_model_get_iter (model
, &iter
, (GtkTreePath
*)selected
->data
))
296 gtk_tree_model_get (model
, &iter
, DATA_COLUMN
, &header
, -1);
298 gtk_tree_path_free ((GtkTreePath
*)selected
->data
);
299 g_list_free (selected
);
302 druid
->header
= header
;
303 gtk_assistant_set_page_complete (GTK_ASSISTANT (druid
->window
), druid
->project_page
, header
!= NULL
);
306 /* Add a project in the icon list */
308 cb_druid_insert_project_icon (gpointer data
, gpointer user_data
)
310 NPWHeader
*header
= (NPWHeader
*)data
;
311 GtkListStore
* store
= GTK_LIST_STORE (user_data
);
315 gtk_list_store_append (store
, &iter
);
316 pixbuf
= gdk_pixbuf_new_from_file (npw_header_get_iconfile (header
), NULL
);
317 gtk_list_store_set (store
, &iter
, PIXBUF_COLUMN
, pixbuf
,
318 TEXT_COLUMN
, npw_header_get_name (header
),
319 DESC_COLUMN
, npw_header_get_description (header
),
323 g_object_unref (pixbuf
);
326 /* Add a page in the project notebook */
328 cb_druid_insert_project_page (gpointer value
, gpointer user_data
)
330 NPWDruid
* druid
= (NPWDruid
*)user_data
;
334 GtkWidget
* assistant
;
338 GList
*template_list
= (GList
*)value
;
339 const gchar
* category
;
341 category
= npw_header_get_category ((NPWHeader
*)template_list
->data
);
343 /* Build another complete wizard dialog from the gtk builder file
344 * but keep only the project selection notebook page */
345 builder
= gtk_builder_new ();
346 if (!gtk_builder_add_from_file (builder
, GTK_BUILDER_UI_FILE
, NULL
))
348 g_warn_if_reached ();
349 g_object_unref (builder
);
354 view
= GTK_ICON_VIEW (gtk_builder_get_object (builder
, PROJECT_LIST
));
355 gtk_icon_view_set_pixbuf_column (view
, PIXBUF_COLUMN
);
356 gtk_icon_view_set_markup_column (view
, TEXT_COLUMN
);
357 store
= gtk_list_store_new (4, GDK_TYPE_PIXBUF
, G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_POINTER
);
358 g_list_foreach (template_list
, cb_druid_insert_project_icon
, store
);
359 gtk_icon_view_set_model (view
, GTK_TREE_MODEL (store
));
361 /* Connect signal to update dialog */
362 g_signal_connect (G_OBJECT (view
), "selection-changed", G_CALLBACK (on_druid_project_update_selected
), druid
);
363 g_signal_connect (G_OBJECT (view
), "map", G_CALLBACK (on_druid_project_update_selected
), druid
);
364 g_signal_connect_swapped (G_OBJECT (view
), "item-activated", G_CALLBACK (gtk_assistant_next_page
), druid
->window
);
366 /* Set new page label */
367 assistant
= GTK_WIDGET (gtk_builder_get_object (builder
, NEW_PROJECT_DIALOG
));
368 book
= GTK_NOTEBOOK (gtk_builder_get_object (builder
, PROJECT_BOOK
));
369 child
= gtk_notebook_get_nth_page (book
, 0);
370 label
= gtk_notebook_get_tab_label (book
, child
);
371 gtk_label_set_text (GTK_LABEL(label
), (const gchar
*)category
);
373 /* Pick up the filled project selection page from the newly created dialog
374 * add it to the wizard project notebook and destroy the dialog
376 gtk_notebook_remove_page (book
, 0);
377 gtk_notebook_append_page (druid
->project_book
, child
, label
);
378 gtk_widget_destroy (assistant
);
380 g_object_unref (builder
);
383 /* Fill project selection page */
385 npw_druid_fill_selection_page (NPWDruid
* druid
, const gchar
*directory
)
388 const gchar
* const * sys_dir
;
390 /* Remove all previous data */
391 gtk_notebook_remove_page(druid
->project_book
, 0);
392 npw_header_list_free (druid
->header_list
);
393 anjuta_autogen_clear_library_path (druid
->gen
);
395 /* Create list of projects */
396 druid
->header_list
= npw_header_list_new ();
398 if (directory
!= NULL
)
400 /* Read project template only in specified directory,
401 * other directories can still be used to get included
403 npw_header_list_readdir (&druid
->header_list
, directory
);
404 anjuta_autogen_set_library_path (druid
->gen
, directory
);
407 dir
= g_build_filename (g_get_user_data_dir (), "anjuta", "project", NULL
);
408 if (directory
== NULL
)
410 /* Read project template in user directory,
411 * normally ~/.local/share/anjuta/project,
412 * the first template read override the others */
413 npw_header_list_readdir (&druid
->header_list
, dir
);
415 anjuta_autogen_set_library_path (druid
->gen
, dir
);
418 for (sys_dir
= g_get_system_data_dirs (); *sys_dir
!= NULL
; sys_dir
++)
420 dir
= g_build_filename (*sys_dir
, "anjuta", "project", NULL
);
421 if (directory
== NULL
)
423 /* Read project template in system directory */
424 npw_header_list_readdir (&druid
->header_list
, dir
);
426 anjuta_autogen_set_library_path (druid
->gen
, dir
);
430 if (directory
== NULL
)
432 /* Read anjuta installation directory */
433 npw_header_list_readdir (&druid
->header_list
, PROJECT_WIZARD_DIRECTORY
);
435 anjuta_autogen_set_library_path (druid
->gen
, PROJECT_WIZARD_DIRECTORY
);
437 if (g_list_length (druid
->header_list
) == 0)
439 anjuta_util_dialog_error (GTK_WINDOW (ANJUTA_PLUGIN (druid
->plugin
)->shell
),_("Unable to find any project template in %s"), PROJECT_WIZARD_DIRECTORY
);
443 /* Add all necessary notebook page */
444 g_list_foreach (druid
->header_list
, cb_druid_insert_project_page
, druid
);
446 gtk_widget_show_all (GTK_WIDGET (druid
->project_book
));
451 /* Create properties pages
452 *---------------------------------------------------------------------------*/
454 /* Group infomation need by the following call back function */
455 typedef struct _NPWDruidAddPropertyData
460 GtkWidget
*first_entry
;
461 } NPWDruidAddPropertyData
;
464 cb_druid_destroy_widget (GtkWidget
* widget
, gpointer user_data
)
466 gtk_widget_destroy (widget
);
470 cb_druid_add_property (NPWProperty
* property
, gpointer user_data
)
474 NPWDruidAddPropertyData
* data
= (NPWDruidAddPropertyData
*)user_data
;
475 const gchar
* description
;
476 GtkAttachOptions attach
= GTK_EXPAND
|GTK_FILL
;
479 entry
= npw_property_create_widget (property
);
482 /* Not hidden property */
483 description
= npw_property_get_description (property
);
485 /* Set description tooltip */
486 if (description
&& (*description
!= '\0'))
488 gtk_widget_set_tooltip_text (entry
, description
);
491 label
= gtk_label_new (npw_property_get_label (property
));
492 gtk_misc_set_alignment (GTK_MISC (label
), 0, 0.5);
493 gtk_misc_set_padding (GTK_MISC (label
), 6, 6);
495 switch (npw_property_get_type (property
))
497 case NPW_PACKAGE_PROPERTY
:
498 gtk_table_resize (data
->table
, data
->row
+ 2, 1);
499 gtk_table_attach (data
->table
, label
, 0, 1, data
->row
, data
->row
+ 1,
500 (GtkAttachOptions
)(GTK_FILL
), 0, 0, 0);
501 gtk_table_attach (data
->table
, entry
, 0, 1, data
->row
+ 1, data
->row
+ 2,
502 (GtkAttachOptions
)(GTK_EXPAND
|GTK_FILL
),
503 (GtkAttachOptions
)(GTK_EXPAND
|GTK_FILL
), 0, 0);
506 case NPW_BOOLEAN_PROPERTY
:
510 /* Add label and entry */
511 gtk_table_resize (data
->table
, data
->row
+ 1, 2);
512 gtk_table_attach (data
->table
, label
, 0, 1, data
->row
, data
->row
+ 1,
513 (GtkAttachOptions
)(GTK_FILL
), 0, 0, 0);
514 gtk_table_attach (data
->table
, entry
, 1, 2, data
->row
, data
->row
+ 1,
515 (GtkAttachOptions
)(attach
), 0, 0, 0);
519 /* Set first entry */
520 if (data
->first_entry
== NULL
) data
->first_entry
= entry
;
525 npw_druid_fill_property_page (NPWDruid
* druid
, NPWPage
* page
)
530 NPWDruidAddPropertyData data
;
532 /* Add page to assistant, after current page */
533 widget
= gtk_assistant_get_nth_page (GTK_ASSISTANT (druid
->window
), gtk_assistant_get_current_page (GTK_ASSISTANT (druid
->window
)) + 1);
535 /* Remove previous widgets */
536 gtk_container_foreach (GTK_CONTAINER (npw_page_get_widget (page
)), cb_druid_destroy_widget
, NULL
);
539 children
= gtk_container_get_children (GTK_CONTAINER (widget
));
540 label
= GTK_LABEL (g_list_nth_data (children
, 0));
541 g_list_free (children
);
542 gtk_label_set_text (label
, npw_page_get_label (page
));
543 gtk_assistant_set_page_title (GTK_ASSISTANT (druid
->window
), widget
, npw_page_get_label (page
));
548 data
.table
= GTK_TABLE (npw_page_get_widget (page
));
549 data
.first_entry
= NULL
;
550 npw_page_foreach_property (page
, (GFunc
)cb_druid_add_property
, &data
);
552 /* Move focus on first entry */
553 if (data
.first_entry
!= NULL
)
555 gtk_container_set_focus_child (GTK_CONTAINER (data
.table
), data
.first_entry
);
558 gtk_widget_show_all (widget
);
562 *---------------------------------------------------------------------------*/
565 npw_druid_add_new_page (NPWDruid
* druid
)
570 /* Get page in cache */
571 current
= gtk_assistant_get_current_page (GTK_ASSISTANT (druid
->window
));
572 page
= g_queue_peek_nth (druid
->page_list
, current
);
576 /* Page not found in cache, create */
579 GtkAssistantPageType type
;
582 GtkAssistant
*assistant
;
584 /* Build another complete wizard dialog from the gtk builder file
585 * but keep only the property assistant page */
586 builder
= gtk_builder_new ();
587 if (!gtk_builder_add_from_file (builder
, GTK_BUILDER_UI_FILE
, NULL
))
589 g_warn_if_reached ();
590 g_object_unref (builder
);
594 assistant
= GTK_ASSISTANT (gtk_builder_get_object (builder
, NEW_PROJECT_DIALOG
));
595 widget
= GTK_WIDGET (gtk_builder_get_object (builder
, PROPERTY_PAGE
));
596 table
= GTK_WIDGET (gtk_builder_get_object (builder
, PROPERTY_TABLE
));
598 type
= gtk_assistant_get_page_type (assistant
, widget
);
599 pixbuf
= gtk_assistant_get_page_header_image (assistant
, widget
);
600 if (pixbuf
) g_object_ref (pixbuf
);
601 gtk_container_remove (GTK_CONTAINER (assistant
), widget
);
602 gtk_assistant_insert_page (GTK_ASSISTANT (druid
->window
), widget
, current
+ 1);
603 gtk_assistant_set_page_type (GTK_ASSISTANT (druid
->window
), widget
, type
);
606 gtk_assistant_set_page_header_image (GTK_ASSISTANT (druid
->window
), widget
, pixbuf
);
607 g_object_ref (pixbuf
);
609 gtk_assistant_set_page_complete (GTK_ASSISTANT (druid
->window
), widget
, TRUE
);
610 gtk_widget_destroy (GTK_WIDGET (assistant
));
612 /* Builder get reference on all built widget, so unref it when all work is done */
613 g_object_unref (builder
);
615 /* Create new page */
616 page
= npw_page_new (druid
->values
);
617 npw_page_set_widget (page
, table
);
619 /* Add page in cache */
620 g_queue_push_tail (druid
->page_list
, page
);
626 /* Remove all pages following current page except the summary page*/
629 npw_druid_remove_following_page (NPWDruid
* druid
)
633 current
= gtk_assistant_get_current_page (GTK_ASSISTANT (druid
->window
));
639 widget
= gtk_assistant_get_nth_page (GTK_ASSISTANT (druid
->window
), current
+ 1);
640 if (widget
== druid
->finish_page
) break;
642 gtk_container_remove (GTK_CONTAINER (druid
->window
), widget
);
644 page
= g_queue_pop_nth (druid
->page_list
, current
- 1);
645 if (page
!= NULL
) npw_page_free (page
);
650 *---------------------------------------------------------------------------*/
652 typedef struct _NPWSaveValidPropertyData
659 } NPWSaveValidPropertyData
;
662 cb_save_valid_property (NPWProperty
* property
, gpointer user_data
)
664 NPWSaveValidPropertyData
* data
= (NPWSaveValidPropertyData
*)user_data
;
668 /* Get value from widget */
669 modified
= npw_property_update_value_from_widget (property
);
670 if (modified
) data
->modified
= modified
;
671 value
= npw_property_get_value (property
);
673 /* Check mandatory property */
674 if (modified
&& (npw_property_get_options (property
) & NPW_MANDATORY_OPTION
))
676 if ((value
== NULL
) || (strlen (value
) <= 0))
678 g_string_append_printf (data
->error
,
679 _("\nField \"%s\" is mandatory. Please enter it."),
680 npw_property_get_label (property
));
681 npw_property_remove_value (property
);
685 /* Check restricted property */
686 if (modified
&& !npw_property_is_valid_restriction (property
))
688 NPWPropertyRestriction restriction
= npw_property_get_restriction (property
);
692 case NPW_FILENAME_RESTRICTION
:
693 g_string_append_printf (data
->error
,
694 _("Field \"%s\" must contains only letters, digits or the following characters \"#$:%%+,.=@^_`~\". In addition you cannot have a leading dash. Please fix it."),
695 npw_property_get_label (property
));
697 case NPW_DIRECTORY_RESTRICTION
:
698 g_string_append_printf (data
->error
,
699 _("Field \"%s\" must contains only letters, digits, the following characters \"#$:%%+,.=@^_`~\" or directory separators. In addition you cannot have a leading dash. Please fix it."),
700 npw_property_get_label (property
));
702 case NPW_PRINTABLE_RESTRICTION
:
703 g_string_append_printf (data
->error
,
704 _("Field \"%s\" must contains only ASCII printable characters, no accentuated characters by example. Please fix it."),
705 npw_property_get_label (property
));
708 g_string_append_printf (data
->error
,
709 _("Unknown error."));
712 npw_property_remove_value (property
);
715 /* Check exist property */
716 if (modified
&& (npw_property_get_exist_option (property
) == NPW_FALSE
))
718 gboolean is_directory
= npw_property_get_type (property
) == NPW_DIRECTORY_PROPERTY
;
719 gboolean exist
= (value
!= NULL
) && g_file_test (value
, G_FILE_TEST_EXISTS
);
720 /* Allow empty directory */
721 if (exist
&& is_directory
)
725 dir
= g_dir_open (value
, 0, NULL
);
728 if (g_dir_read_name (dir
) == NULL
) exist
= FALSE
;
735 g_string_append_printf (data
->warning
, is_directory
?
736 _("Directory \"%s\" is not empty. Project creation could fail if some files "
737 "cannot be written. Do you want to continue?") :
738 _("File \"%s\" already exists. Do you want to overwrite it?"),
744 /* Save values and check them, return TRUE if it's possible to go to
748 npw_druid_save_valid_values (NPWDruid
* druid
)
752 NPWSaveValidPropertyData data
;
755 current
= gtk_assistant_get_current_page (GTK_ASSISTANT (druid
->window
)) - 2;
756 page
= g_queue_peek_nth (druid
->page_list
, current
);
757 data
.modified
= FALSE
;
758 data
.parent
= GTK_WINDOW (druid
->window
);
759 data
.error
= g_string_new (NULL
);
760 data
.warning
= g_string_new (NULL
);
761 npw_page_foreach_property (page
, (GFunc
)cb_save_valid_property
, &data
);
763 if (data
.modified
) npw_druid_remove_following_page (druid
);
767 npw_druid_fill_error_page (druid
, NULL
,
775 else if (data
.warning
->len
)
777 npw_druid_fill_error_page (druid
, NULL
,
786 g_string_free (data
.error
, TRUE
);
787 g_string_free (data
.warning
, TRUE
);
792 /* Druid GUI functions
793 *---------------------------------------------------------------------------*/
796 npw_druid_set_busy (NPWDruid
*druid
, gboolean busy_state
)
798 if (druid
->busy
== busy_state
)
803 anjuta_status_busy_push (anjuta_shell_get_status (ANJUTA_PLUGIN (druid
->plugin
)->shell
, NULL
));
805 anjuta_status_busy_pop (anjuta_shell_get_status (ANJUTA_PLUGIN (druid
->plugin
)->shell
, NULL
));
806 druid
->busy
= busy_state
;
810 *---------------------------------------------------------------------------*/
813 on_druid_cancel (GtkAssistant
* window
, NPWDruid
* druid
)
815 anjuta_plugin_deactivate (ANJUTA_PLUGIN (druid
->plugin
));
816 npw_druid_free (druid
);
820 on_druid_close (GtkAssistant
* window
, NPWDruid
* druid
)
822 anjuta_plugin_deactivate (ANJUTA_PLUGIN (druid
->plugin
));
823 npw_druid_free (druid
);
827 on_project_wizard_key_press_event(GtkWidget
*widget
, GdkEventKey
*event
,
830 if (event
->keyval
== GDK_KEY_Escape
)
832 on_druid_cancel (GTK_ASSISTANT (widget
), druid
);
839 on_druid_get_new_page (AnjutaAutogen
* gen
, gpointer data
)
841 NPWDruid
* druid
= (NPWDruid
*)data
;
845 current
= gtk_assistant_get_current_page (GTK_ASSISTANT (druid
->window
));
846 page
= g_queue_peek_nth (druid
->page_list
, current
- 1);
848 if (npw_page_get_name (page
) == NULL
)
850 /* no page, display finish page */
851 npw_druid_fill_summary_page (druid
);
853 page
= g_queue_pop_nth (druid
->page_list
, current
- 1);
854 if (page
!= NULL
) npw_page_free (page
);
855 gtk_container_remove (GTK_CONTAINER (druid
->window
), gtk_assistant_get_nth_page (GTK_ASSISTANT (druid
->window
), current
+ 1));
856 gtk_assistant_set_current_page (GTK_ASSISTANT (druid
->window
), current
+ 1);
860 /* display property page */
861 npw_druid_fill_property_page (druid
, page
);
863 gtk_assistant_set_current_page (GTK_ASSISTANT (druid
->window
), current
+ 1);
868 on_druid_parse_page (const gchar
* output
, gpointer data
)
870 GError
*error
= NULL
;
871 NPWPageParser
* parser
= (NPWPageParser
*)data
;
873 npw_page_parser_parse (parser
, output
, strlen (output
), &error
);
877 g_warning ("Parser error: %s", error
->message
);
878 g_error_free (error
);
883 strip_package_version_info (gpointer data
, gpointer user_data
)
885 gchar
* const pkg
= (gchar
*) data
;
889 g_strdelimit (pkg
, " ", '\0');
893 on_install_button_clicked (GtkWidget
*button
, NPWDruid
*druid
)
895 GList
*missing_programs
, *missing_packages
;
896 GList
*missing_files
= NULL
;
900 missing_programs
= npw_header_check_required_programs (druid
->header
);
901 missing_packages
= npw_header_check_required_packages (druid
->header
);
903 anjuta_util_glist_strings_prefix (missing_programs
, "/usr/bin/");
905 /* Search for "pkgconfig(pkg_name)" */
906 g_list_foreach (missing_packages
, (GFunc
) strip_package_version_info
,
908 missing_files
= g_list_concat (missing_files
, missing_programs
);
910 for (node
= missing_packages
; node
!= NULL
; node
= g_list_next (missing_packages
))
912 gchar
* pk_pkg_config_string
= g_strdup_printf ("pkgconfig(%s)", (gchar
*) node
->data
);
913 missing_files
= g_list_append (missing_files
, pk_pkg_config_string
);
915 g_list_free (missing_packages
);
919 gchar
* missing_names
= NULL
;
921 missing_names
= anjuta_util_glist_strings_join (missing_files
, ", ");
922 anjuta_util_install_files (missing_names
);
925 g_free (missing_names
);
926 anjuta_util_glist_strings_free (missing_files
);
931 check_and_warn_missing (NPWDruid
*druid
)
933 GList
*missing_programs
, *missing_packages
;
934 GString
*missing_message
= NULL
;
936 missing_programs
= npw_header_check_required_programs (druid
->header
);
937 missing_packages
= npw_header_check_required_packages (druid
->header
);
939 if (missing_programs
|| missing_packages
)
941 missing_message
= g_string_new (NULL
);
944 if (missing_programs
)
946 gchar
*missing_progs
;
947 missing_progs
= anjuta_util_glist_strings_join (missing_programs
,
949 g_string_append_printf (missing_message
,
950 _("\nMissing programs: %s."), missing_progs
);
951 g_free (missing_progs
);
952 anjuta_util_glist_strings_free (missing_programs
);
955 if (missing_packages
)
958 missing_pkgs
= anjuta_util_glist_strings_join (missing_packages
,
960 g_string_append_printf (missing_message
,
961 _("\nMissing packages: %s."), missing_pkgs
);
962 g_free (missing_pkgs
);
963 anjuta_util_glist_strings_free (missing_packages
);
968 GtkWidget
*hbox
, *install_button
;
969 g_string_prepend (missing_message
, _(
970 "Some important programs or development packages required to build "
971 "this project are missing. Please make sure they are "
972 "installed properly before generating the project.\n"));
974 hbox
= gtk_hbox_new (FALSE
, 0);
975 gtk_widget_show (hbox
);
977 #ifdef ENABLE_PACKAGEKIT
979 gtk_button_new_with_label (_("Install missing packages"));
980 gtk_box_pack_end (GTK_BOX (hbox
), install_button
, FALSE
, FALSE
, 10);
981 g_signal_connect (install_button
, "clicked",
982 G_CALLBACK (on_install_button_clicked
), druid
);
983 gtk_widget_show (install_button
);
986 npw_druid_fill_error_page (druid
, hbox
,
988 /* Translators: Application Manager is the program used to install
989 * new application like apt on Ubuntu, yum on Fedora, zypper on
990 * OpenSuSE and emerge on Gentoo */
991 _("The missing programs are usually part of some distribution "
992 "packages and can be searched for in your Application Manager. "
993 "Similarly, the development packages are contained in special "
994 "packages that your distribution provides to allow development "
995 "of projects based on them. They usually end with a \"-dev\" or "
996 "\"-devel\" suffix in package names and can be found by searching "
997 "in your Application Manager."),
999 _("Missing components"),
1000 missing_message
->str
);
1001 g_string_free (missing_message
, TRUE
);
1004 return !missing_message
;
1009 on_druid_real_prepare (GtkAssistant
* assistant
, GtkWidget
*page
, NPWDruid
* druid
)
1011 if (page
== druid
->progress_page
)
1014 gboolean last_warning
;
1016 previous
= gtk_assistant_get_current_page (assistant
) - 1;
1017 last_warning
= gtk_assistant_get_nth_page (assistant
, previous
) == druid
->error_page
;
1020 /* Remove warning page */
1021 gtk_container_remove (GTK_CONTAINER (assistant
), druid
->error_page
);
1025 /* Generate the next page */
1026 if (previous
== PROJECT_PAGE_INDEX
)
1028 const gchar
* new_project
;
1030 new_project
= npw_header_get_filename (druid
->header
);
1032 if (druid
->project_file
!= new_project
)
1034 npw_druid_remove_following_page (druid
);
1036 /* Check if necessary programs for this project is installed */
1037 if (!last_warning
&& !check_and_warn_missing (druid
))
1039 gtk_assistant_set_current_page (assistant
, gtk_assistant_get_current_page (assistant
) + 1);
1043 /* Change project */
1044 druid
->project_file
= new_project
;
1045 anjuta_autogen_set_input_file (druid
->gen
, druid
->project_file
, "[+","+]");
1051 if (!npw_druid_save_valid_values (druid
))
1054 gtk_assistant_set_current_page (assistant
, gtk_assistant_get_current_page (assistant
) + 1);
1060 if (g_queue_peek_nth (druid
->page_list
, previous
) == NULL
)
1062 /* Regenerate new page */
1063 gtk_assistant_set_page_complete (assistant
, page
, FALSE
);
1064 if (druid
->parser
!= NULL
)
1065 npw_page_parser_free (druid
->parser
);
1066 druid
->parser
= npw_page_parser_new (npw_druid_add_new_page (druid
), druid
->project_file
, previous
);
1068 anjuta_autogen_set_output_callback (druid
->gen
, on_druid_parse_page
, druid
->parser
);
1069 anjuta_autogen_write_definition_file (druid
->gen
, druid
->values
, NULL
);
1070 anjuta_autogen_execute (druid
->gen
, on_druid_get_new_page
, druid
, NULL
);
1074 /* Page is already in cache, change the page to display it */
1075 on_druid_get_new_page (NULL
, druid
);
1078 else if (page
== druid
->finish_page
)
1080 npw_druid_set_busy (druid
, FALSE
);
1081 gtk_container_remove (GTK_CONTAINER (assistant
), druid
->error_page
);
1082 gtk_container_remove (GTK_CONTAINER (assistant
), druid
->progress_page
);
1086 npw_druid_set_busy (druid
, FALSE
);
1088 if (page
!= druid
->error_page
) gtk_container_remove (GTK_CONTAINER (assistant
), druid
->error_page
);
1090 /* Move progress page */
1091 gtk_container_remove (GTK_CONTAINER (assistant
), druid
->progress_page
);
1092 gtk_assistant_insert_page (assistant
, druid
->progress_page
, gtk_assistant_get_current_page (assistant
) + 1);
1093 gtk_assistant_set_page_title (assistant
, druid
->progress_page
, "...");
1098 on_druid_delayed_prepare (gpointer data
)
1100 NPWDruid
*druid
= (NPWDruid
*)data
;
1101 GtkAssistant
*assistant
;
1104 assistant
= GTK_ASSISTANT (druid
->window
);
1105 page
= gtk_assistant_get_nth_page (assistant
, gtk_assistant_get_current_page (assistant
));
1106 on_druid_real_prepare (assistant
, page
, druid
);
1112 on_druid_prepare (GtkAssistant
* assistant
, GtkWidget
*page
, NPWDruid
* druid
)
1114 /* The page change is delayed because in the latest version of
1115 * GtkAssistant, the page switch is not completely done when
1116 * the signal is called. A page change in the signal handler
1117 * will be partialy overwritten */
1118 g_idle_add (on_druid_delayed_prepare
, druid
);
1123 on_druid_finish (GtkAssistant
* assistant
, NPWDruid
* druid
)
1128 inst
= npw_install_new (druid
->plugin
);
1129 npw_install_set_property (inst
, druid
->values
);
1130 npw_install_set_wizard_file (inst
, npw_header_get_filename (druid
->header
));
1131 for (path
= g_list_last (anjuta_autogen_get_library_paths (druid
->gen
)); path
!= NULL
; path
= g_list_previous (path
))
1133 npw_install_set_library_path (inst
, (const gchar
*)path
->data
);
1135 npw_install_launch (inst
);
1139 npw_druid_create_assistant (NPWDruid
* druid
, const gchar
*directory
)
1142 GtkBuilder
*builder
;
1143 GError
* error
= NULL
;
1144 GtkAssistant
*assistant
;
1145 GtkWidget
*property_page
;
1147 g_return_val_if_fail (druid
->window
== NULL
, NULL
);
1149 shell
= ANJUTA_PLUGIN (druid
->plugin
)->shell
;
1151 /* Create GtkAssistant using GtkBuilder, glade doesn't seem to work*/
1152 builder
= gtk_builder_new ();
1153 if (!gtk_builder_add_from_file (builder
, GTK_BUILDER_UI_FILE
, &error
))
1155 g_warning ("Couldn't load builder file: %s", error
->message
);
1156 g_error_free (error
);
1159 anjuta_util_builder_get_objects (builder
,
1160 NEW_PROJECT_DIALOG
, &assistant
,
1161 PROJECT_BOOK
, &druid
->project_book
,
1162 ERROR_VBOX
, &druid
->error_vbox
,
1163 ERROR_TITLE
, &druid
->error_title
,
1164 ERROR_ICON
, &druid
->error_icon
,
1165 ERROR_MESSAGE
, &druid
->error_message
,
1166 ERROR_DETAIL
, &druid
->error_detail
,
1167 PROJECT_PAGE
, &druid
->project_page
,
1168 ERROR_PAGE
, &druid
->error_page
,
1169 PROGRESS_PAGE
, &druid
->progress_page
,
1170 FINISH_PAGE
, &druid
->finish_page
,
1171 FINISH_TEXT
, &druid
->finish_text
,
1172 PROPERTY_PAGE
, &property_page
,
1174 druid
->window
= GTK_WINDOW (assistant
);
1175 g_object_ref (druid
->error_page
);
1176 g_object_ref (druid
->progress_page
);
1177 gtk_window_set_transient_for (GTK_WINDOW (assistant
), GTK_WINDOW (shell
));
1178 g_object_unref (builder
);
1180 /* Connect assistant signals */
1181 g_signal_connect (G_OBJECT (assistant
), "prepare", G_CALLBACK (on_druid_prepare
), druid
);
1182 g_signal_connect (G_OBJECT (assistant
), "apply", G_CALLBACK (on_druid_finish
), druid
);
1183 g_signal_connect (G_OBJECT (assistant
), "cancel", G_CALLBACK (on_druid_cancel
), druid
);
1184 g_signal_connect (G_OBJECT (assistant
), "close", G_CALLBACK (on_druid_close
), druid
);
1185 g_signal_connect(G_OBJECT(assistant
), "key-press-event", G_CALLBACK(on_project_wizard_key_press_event
), druid
);
1187 /* Remove property page, will be created later as needed */
1188 gtk_container_remove (GTK_CONTAINER (assistant
), property_page
);
1190 /* Setup project selection page */
1191 if (!npw_druid_fill_selection_page (druid
, directory
))
1196 /* Add dialog widget to anjuta status. */
1197 anjuta_status_add_widget (anjuta_shell_get_status (shell
, NULL
), GTK_WIDGET (assistant
));
1199 gtk_window_set_default_size (GTK_WINDOW (assistant
),
1202 gtk_widget_show_all (GTK_WIDGET (assistant
));
1204 return GTK_WIDGET(assistant
);
1207 /* Add default property
1208 *---------------------------------------------------------------------------*/
1211 npw_druid_add_default_property (NPWDruid
* druid
)
1214 AnjutaPreferences
* pref
;
1215 GSettings
*settings
;
1219 pref
= anjuta_shell_get_preferences (ANJUTA_PLUGIN (druid
->plugin
)->shell
, NULL
);
1221 /* Add default base project directory */
1222 g_hash_table_insert (druid
->values
, g_strdup (ANJUTA_PROJECT_DIRECTORY_PROPERTY
), g_strdup (g_get_home_dir()));
1225 g_hash_table_insert (druid
->values
, g_strdup (USER_NAME_PROPERTY
), g_strdup (g_get_real_name()));
1227 /* Add Email address */
1228 /* FIXME: We need a default way for the mail */
1229 s
= anjuta_util_get_user_mail();
1230 g_hash_table_insert (druid
->values
, g_strdup (EMAIL_ADDRESS_PROPERTY
), s
);
1232 /* Add use-tabs property */
1233 settings
= g_settings_new (ANJUTA_PREF_SCHEMA_PREFIX IANJUTA_EDITOR_PREF_SCHEMA
);
1234 flag
= g_settings_get_boolean (settings
, IANJUTA_EDITOR_USE_TABS_KEY
);
1235 g_hash_table_insert (druid
->values
, g_strdup (USE_TABS_PROPERTY
), g_strdup (flag
? "1" : "0"));
1237 /* Add tab-width property */
1238 i
= g_settings_get_int (settings
, IANJUTA_EDITOR_TAB_WIDTH_KEY
);
1239 g_hash_table_insert (druid
->values
, g_strdup (TAB_WIDTH_PROPERTY
), g_strdup_printf("%d", i
));
1241 /* Add indent-width property */
1242 i
= g_settings_get_int (settings
, IANJUTA_EDITOR_INDENT_WIDTH_KEY
);
1243 g_hash_table_insert (druid
->values
, g_strdup (INDENT_WIDTH_PROPERTY
), g_strdup_printf("%d", i
));
1244 g_object_unref (settings
);
1247 /* Druid public functions
1248 *---------------------------------------------------------------------------*/
1251 npw_druid_new (NPWPlugin
* plugin
, const gchar
*directory
)
1255 /* Check if autogen is present */
1256 if (!anjuta_check_autogen())
1258 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."));
1262 druid
= g_new0(NPWDruid
, 1);
1263 druid
->plugin
= plugin
;
1264 druid
->project_file
= NULL
;
1265 druid
->busy
= FALSE
;
1266 druid
->page_list
= g_queue_new ();
1267 druid
->values
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, (GDestroyNotify
)g_free
);
1268 druid
->gen
= anjuta_autogen_new ();
1269 druid
->plugin
= plugin
;
1270 druid
->error_extra_widget
= NULL
;
1272 if (npw_druid_create_assistant (druid
, directory
) == NULL
)
1274 npw_druid_free (druid
);
1279 npw_druid_add_default_property (druid
);
1285 npw_druid_free (NPWDruid
* druid
)
1289 g_return_if_fail (druid
!= NULL
);
1291 /* Delete page list */
1293 while ((page
= (NPWPage
*)g_queue_pop_head (druid
->page_list
)) != NULL
)
1295 npw_page_free (page
);
1297 g_queue_free (druid
->page_list
);
1298 g_hash_table_destroy (druid
->values
);
1299 anjuta_autogen_free (druid
->gen
);
1300 if (druid
->parser
!= NULL
) npw_page_parser_free (druid
->parser
);
1301 npw_header_list_free (druid
->header_list
);
1302 gtk_widget_destroy (GTK_WIDGET (druid
->window
));
1303 g_object_unref (druid
->error_page
);
1304 g_object_unref (druid
->progress_page
);
1305 druid
->plugin
->druid
= NULL
;
1310 npw_druid_show (NPWDruid
* druid
)
1312 g_return_if_fail (druid
!= NULL
);
1314 /* Display dialog box */
1315 if (druid
->window
) gtk_window_present (druid
->window
);