Revision: 1200 http://svn.sourceforge.net/geany/?rev=1200&view=rev Author: eht16 Date: 2007-01-17 15:44:08 -0800 (Wed, 17 Jan 2007)
Log Message: ----------- Added properties dialog (still far away from state ready). Added file_patterns field. Added utils_mkdir().
Modified Paths: -------------- trunk/ChangeLog trunk/src/project.c trunk/src/project.h trunk/src/utils.c trunk/src/utils.h
Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2007-01-17 17:42:23 UTC (rev 1199) +++ trunk/ChangeLog 2007-01-17 23:44:08 UTC (rev 1200) @@ -1,3 +1,11 @@ +2007-01-17 Enrico Tröger enrico.troeger@uvena.de + + * src/project.c, src/project.h: + Added properties dialog (still far away from state ready). + Added file_patterns field. + * src/utils.c, src/utils.h: Added utils_mkdir(). + + 2007-01-17 Nick Treleaven nick.treleaven@btinternet.com
* src/callbacks.c, doc/geany.docbook:
Modified: trunk/src/project.c =================================================================== --- trunk/src/project.c 2007-01-17 17:42:23 UTC (rev 1199) +++ trunk/src/project.c 2007-01-17 23:44:08 UTC (rev 1200) @@ -22,19 +22,44 @@ */
#include "geany.h" + +#include <string.h> + #include "project.h" #include "dialogs.h" #include "support.h" +#include "utils.h" +#include "ui_utils.h" +#ifdef G_OS_WIN32 +# include "win32.h" +#endif
+ +// simple struct to keep references to the elements of the properties dialog +typedef struct +{ + GtkWidget *dialog; + GtkWidget *name; + GtkWidget *description; + GtkWidget *file_name; + GtkWidget *base_path; + GtkWidget *patterns; +} PropertyDialogElements; + + + +static void on_properties_dialog_response(GtkDialog *dialog, gint response, + PropertyDialogElements *e); +static void on_file_open_button_clicked(GtkButton *button, GtkWidget *entry); +static void on_folder_open_button_clicked(GtkButton *button, GtkWidget *entry); static gboolean close_open_project(); +static void on_name_entry_changed(GtkEditable *editable, PropertyDialogElements *e);
void project_new() { if (! close_open_project()) return;
- // simply create an empty project and show the properties dialog - app->project = g_new0(GeanyProject, 1); project_properties(); }
@@ -66,11 +91,167 @@
void project_properties() { - g_return_if_fail(app->project != NULL); + gchar *ok_button; + GtkWidget *vbox; + GtkWidget *table; + GtkWidget *image; + GtkWidget *button; + GtkWidget *bbox; + GtkWidget *label; + GtkWidget *swin; + PropertyDialogElements *e = g_new(PropertyDialogElements, 1); + + if (app->project == NULL) + ok_button = GTK_STOCK_NEW; + else + ok_button = GTK_STOCK_OK; + + e->dialog = gtk_dialog_new_with_buttons(_("Project properties"), GTK_WINDOW(app->window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + ok_button, GTK_RESPONSE_OK, NULL); + vbox = ui_dialog_vbox_new(GTK_DIALOG(e->dialog)); + + + table = gtk_table_new(5, 2, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), 5); + gtk_table_set_col_spacings(GTK_TABLE(table), 10); + + label = gtk_label_new(_("Name:")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0); + + e->name = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), e->name, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new(_("Description:")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0); + + e->description = gtk_text_view_new(); + swin = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(swin), GTK_WIDGET(e->description)); + gtk_table_attach(GTK_TABLE(table), swin, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new(_("File location:")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0); + + e->file_name = gtk_entry_new(); + button = gtk_button_new(); + g_signal_connect((gpointer) button, "clicked", + G_CALLBACK(on_file_open_button_clicked), e->file_name); + image = gtk_image_new_from_stock("gtk-open", GTK_ICON_SIZE_BUTTON); + gtk_container_add(GTK_CONTAINER(button), image); + bbox = gtk_hbox_new(FALSE, 6); + gtk_box_pack_start_defaults(GTK_BOX(bbox), e->file_name); + gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); + gtk_table_attach(GTK_TABLE(table), bbox, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new(_("Base path:")); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0); + + e->base_path = gtk_entry_new(); + button = gtk_button_new(); + g_signal_connect((gpointer) button, "clicked", + G_CALLBACK(on_folder_open_button_clicked), e->base_path); + image = gtk_image_new_from_stock("gtk-open", GTK_ICON_SIZE_BUTTON); + gtk_container_add(GTK_CONTAINER(button), image); + bbox = gtk_hbox_new(FALSE, 6); + gtk_box_pack_start_defaults(GTK_BOX(bbox), e->base_path); + gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); + gtk_table_attach(GTK_TABLE(table), bbox, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new(_("File patterns:")); + // <small>Separate multiple patterns by a new line</small> + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0); + + e->patterns = gtk_text_view_new(); + swin = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(swin), GTK_WIDGET(e->patterns)); + gtk_table_attach(GTK_TABLE(table), swin, 1, 2, 4, 5, + (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + + + gtk_container_add(GTK_CONTAINER(vbox), table); + + // signals + if (app->project == NULL) + { // this should only be done when we are about to create a new project + g_signal_connect((gpointer) e->name, "changed", G_CALLBACK(on_name_entry_changed), e); + // run the callback manually to initialise the base_path and file_name fields + on_name_entry_changed(GTK_EDITABLE(e->name), e); + } + g_signal_connect((gpointer) e->dialog, "response", + G_CALLBACK(on_properties_dialog_response), e); + + // if we have an already open project, fill the elements with the appropriate data + if (app->project != NULL) + { + GeanyProject *p = app->project; + + gtk_entry_set_text(GTK_ENTRY(e->name), p->name); + + if (p->description != NULL) + { // set text + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(e->description)); + gtk_text_buffer_set_text(buffer, p->description, -1); + } + + if (p->file_patterns != NULL) + { // set the file patterns + gint i; + gint len = g_strv_length(p->file_patterns); + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(e->patterns)); + GString *str = g_string_sized_new(len * 4); + + for (i = 0; i < len; i++) + { + if (p->file_patterns[i] != NULL) + { + g_string_append(str, p->file_patterns[i]); + g_string_append_c(str, '\n'); + } + } + gtk_text_buffer_set_text(buffer, str->str, -1); + g_string_free(str, FALSE); // can this leak? + } + + gtk_entry_set_text(GTK_ENTRY(e->file_name), p->file_name); + gtk_entry_set_text(GTK_ENTRY(e->base_path), p->base_path); + } + + gtk_widget_show_all(e->dialog); }
-/* checks whether there is an already open project and asks the user if he want to close it or +/* checks whether there is an already open project and asks the user if he wants to close it or * abort the current action. Returns FALSE when the current action(the caller) should be cancelled * and TRUE if we can go ahead */ static gboolean close_open_project() @@ -91,3 +272,233 @@ else return TRUE; } + + +#define SHOW_ERR(...) dialogs_show_msgbox(GTK_MESSAGE_ERROR, __VA_ARGS__) +#define MAX_LEN 50 + +static void on_properties_dialog_response(GtkDialog *dialog, gint response, + PropertyDialogElements *e) +{ + if (response == GTK_RESPONSE_OK && e != NULL) + { + const gchar *name, *file_name, *base_path; + gint name_len; + GeanyProject *p; + + name = gtk_entry_get_text(GTK_ENTRY(e->name)); + name_len = strlen(name); + if (name_len == 0) + { + SHOW_ERR(_("The specified project name is too short.")); + gtk_widget_grab_focus(e->name); + return; + } + else if (name_len > MAX_LEN) + { + SHOW_ERR(_("The specified project name is too long (max. %d characters)."), MAX_LEN); + gtk_widget_grab_focus(e->name); + return; + } + + file_name = gtk_entry_get_text(GTK_ENTRY(e->file_name)); + if (strlen(file_name) == 0) + { + SHOW_ERR(_("You have specified an invalid project file location.")); + gtk_widget_grab_focus(e->file_name); + return; + } + + base_path = gtk_entry_get_text(GTK_ENTRY(e->base_path)); + if (strlen(base_path) == 0) + { + SHOW_ERR(_("You have specified an invalid project base path.")); + gtk_widget_grab_focus(e->base_path); + return; + } + else + { // check whether the given directory actually exists + gchar *locale_path = utils_get_locale_from_utf8(base_path); + if (! g_file_test(locale_path, G_FILE_TEST_IS_DIR)) + { + if (dialogs_show_question( + _("The specified project base path does not exist. Should it be created?"))) + { + utils_mkdir(locale_path); + } + else + { + g_free(locale_path); + gtk_widget_grab_focus(e->base_path); + return; + } + } + g_free(locale_path); + } + + // finally test whether the given project file can be written + if (utils_write_file(file_name, "") != 0) + { + SHOW_ERR(_("Project file could not be written.")); + gtk_widget_grab_focus(e->file_name); + return; + } + + app->project = g_new0(GeanyProject, 1); + p = app->project; + + p->name = g_strdup(name); + { // get and set the project description + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(e->description)); + GtkTextIter start, end; + gtk_text_buffer_get_start_iter(buffer, &start); + gtk_text_buffer_get_end_iter(buffer, &end); + p->description = gtk_text_buffer_get_text(buffer, &start, &end, FALSE); + } + p->file_name = g_strdup(file_name); + p->base_path = g_strdup(base_path); + + { // get and set the project file patterns + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(e->patterns)); + GtkTextIter start, end; + gchar *tmp; + gtk_text_buffer_get_start_iter(buffer, &start); + gtk_text_buffer_get_end_iter(buffer, &end); + tmp = gtk_text_buffer_get_text(buffer, &start, &end, FALSE); + g_strfreev(p->file_patterns); + p->file_patterns = g_strsplit(tmp, "\n", -1); + g_free(tmp); + } + } + + gtk_widget_destroy(GTK_WIDGET(dialog)); + g_free(e); +} + + +static void on_file_open_button_clicked(GtkButton *button, GtkWidget *entry) +{ +#ifdef G_OS_WIN32 + /// TODO write me + //win32_show_project_file_dialog(item); +#else + GtkWidget *dialog; + + // initialise the dialog + dialog = gtk_file_chooser_dialog_new(_("Choose project filename"), NULL, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); + gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE); + gtk_window_set_skip_taskbar_hint(GTK_WINDOW(dialog), TRUE); + gtk_window_set_type_hint(GTK_WINDOW(dialog), GDK_WINDOW_TYPE_HINT_DIALOG); + gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT); + + { // set filename + gchar *locale_filename = utils_get_locale_from_utf8(gtk_entry_get_text(GTK_ENTRY(entry))); + + if (g_path_is_absolute(locale_filename)) + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), locale_filename); + else + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), locale_filename); + g_free(locale_filename); + } + + // run it + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + gchar *utf8_filename = utils_get_utf8_from_locale(filename); + + gtk_entry_set_text(GTK_ENTRY(entry), utf8_filename); + + g_free(utf8_filename); + g_free(filename); + } + + gtk_widget_destroy(dialog); +#endif +} + + +static void on_folder_open_button_clicked(GtkButton *button, GtkWidget *entry) +{ +#ifdef G_OS_WIN32 + /// TODO write me + //win32_show_project_folder_dialog(item); +#else + GtkWidget *dialog; + + // initialise the dialog + dialog = gtk_file_chooser_dialog_new(_("Choose project base path"), NULL, + GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); + gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE); + gtk_window_set_skip_taskbar_hint(GTK_WINDOW(dialog), TRUE); + gtk_window_set_type_hint(GTK_WINDOW(dialog), GDK_WINDOW_TYPE_HINT_DIALOG); + gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT); + + { // set filename + gchar *locale_filename = utils_get_locale_from_utf8(gtk_entry_get_text(GTK_ENTRY(entry))); + + if (g_path_is_absolute(locale_filename)) + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), locale_filename); + else + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), locale_filename); + g_free(locale_filename); + } + + // run it + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + gchar *utf8_filename = utils_get_utf8_from_locale(filename); + + gtk_entry_set_text(GTK_ENTRY(entry), utf8_filename); + + g_free(utf8_filename); + g_free(filename); + } + + gtk_widget_destroy(dialog); +#endif +} + +// "projects" is part of the default project base path so be carefully when translating +// please avoid special characters and spaces, look at the source for details or ask Frank +#define PROJECT_DIR _("projects") + +/* sets the project base path and the project file name according to the project name */ +/// TODO cancel the process once base_path resp. file_name has been changed manually +static void on_name_entry_changed(GtkEditable *editable, PropertyDialogElements *e) +{ + gchar *base_path; + gchar *file_name; + gchar *name; + + name = gtk_editable_get_chars(editable, 0, -1); + if (name != NULL && strlen(name) > 0) + { + base_path = g_strconcat( + GEANY_HOME_DIR, G_DIR_SEPARATOR_S, PROJECT_DIR, G_DIR_SEPARATOR_S, + name, G_DIR_SEPARATOR_S, NULL); + file_name = g_strconcat( + GEANY_HOME_DIR, G_DIR_SEPARATOR_S, PROJECT_DIR, G_DIR_SEPARATOR_S, + name, G_DIR_SEPARATOR_S, name, ".geany", NULL); + g_free(name); + } + else + { + base_path = g_strconcat( + GEANY_HOME_DIR, G_DIR_SEPARATOR_S, PROJECT_DIR, G_DIR_SEPARATOR_S, NULL); + file_name = g_strconcat( + GEANY_HOME_DIR, G_DIR_SEPARATOR_S,PROJECT_DIR, G_DIR_SEPARATOR_S, NULL); + } + + gtk_entry_set_text(GTK_ENTRY(e->base_path), base_path); + gtk_entry_set_text(GTK_ENTRY(e->file_name), file_name); + + g_free(base_path); + g_free(file_name); +}
Modified: trunk/src/project.h =================================================================== --- trunk/src/project.h 2007-01-17 17:42:23 UTC (rev 1199) +++ trunk/src/project.h 2007-01-17 23:44:08 UTC (rev 1200) @@ -38,7 +38,7 @@ gchar *executable; // name of the project executable // ... // fields for build process(run arguments and so on) should be added
- + gchar **file_patterns; // array of filename extension patterns };
Modified: trunk/src/utils.c =================================================================== --- trunk/src/utils.c 2007-01-17 17:42:23 UTC (rev 1199) +++ trunk/src/utils.c 2007-01-17 23:44:08 UTC (rev 1200) @@ -781,11 +781,7 @@ if (! g_file_test(dir, G_FILE_TEST_EXISTS)) { geany_debug("creating config directory %s", dir); -#ifdef G_OS_WIN32 - if (mkdir(dir) != 0) error_nr = errno; -#else - if (mkdir(dir, 0700) != 0) error_nr = errno; -#endif + error_nr = utils_mkdir(dir); }
if (error_nr == 0 && ! g_file_test(conf_file, G_FILE_TEST_EXISTS)) @@ -807,11 +803,7 @@
if (! g_file_test(filedefs_dir, G_FILE_TEST_EXISTS)) { -#ifdef G_OS_WIN32 - if (mkdir(filedefs_dir) != 0) error_nr = errno; -#else - if (mkdir(filedefs_dir, 0700) != 0) error_nr = errno; -#endif + error_nr = utils_mkdir(filedefs_dir); } if (error_nr == 0 && ! g_file_test(filedefs_readme, G_FILE_TEST_EXISTS)) { @@ -833,11 +825,7 @@
if (! g_file_test(templates_dir, G_FILE_TEST_EXISTS)) { -#ifdef G_OS_WIN32 - if (mkdir(templates_dir) != 0) error_nr = errno; -#else - if (mkdir(templates_dir, 0700) != 0) error_nr = errno; -#endif + error_nr = utils_mkdir(templates_dir); } if (error_nr == 0 && ! g_file_test(templates_readme, G_FILE_TEST_EXISTS)) { @@ -1481,3 +1469,15 @@ }
+gint utils_mkdir(const gchar *path) +{ + if (path == NULL || strlen(path) == 0) + return EFAULT; + +#ifdef G_OS_WIN32 + if (mkdir(path) != 0) return errno; +#else + if (mkdir(path, 0700) != 0) return errno; +#endif + return 0; +}
Modified: trunk/src/utils.h =================================================================== --- trunk/src/utils.h 2007-01-17 17:42:23 UTC (rev 1199) +++ trunk/src/utils.h 2007-01-17 23:44:08 UTC (rev 1200) @@ -154,4 +154,6 @@ * it will also be freed, the list should be ended with NULL */ void utils_free_pointers(gpointer first, ...);
+gint utils_mkdir(const gchar *path); + #endif
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.