Revision: 1016 http://geany-plugins.svn.sourceforge.net/geany-plugins/?rev=1016&view=re... Author: funto66 Date: 2009-10-18 13:17:02 +0000 (Sun, 18 Oct 2009)
Log Message: ----------- [CodeNav] : restructured the plug-in in multiple files : it's much, much clearer now :)
Modified Paths: -------------- trunk/geany-plugins/codenav/src/Makefile.am trunk/geany-plugins/codenav/src/codenavigation.c
Added Paths: ----------- trunk/geany-plugins/codenav/src/codenavigation.h trunk/geany-plugins/codenav/src/goto_file.c trunk/geany-plugins/codenav/src/goto_file.h trunk/geany-plugins/codenav/src/switch_head_impl.c trunk/geany-plugins/codenav/src/switch_head_impl.h trunk/geany-plugins/codenav/src/utils.c trunk/geany-plugins/codenav/src/utils.h
Modified: trunk/geany-plugins/codenav/src/Makefile.am =================================================================== --- trunk/geany-plugins/codenav/src/Makefile.am 2009-10-18 13:14:05 UTC (rev 1015) +++ trunk/geany-plugins/codenav/src/Makefile.am 2009-10-18 13:17:02 UTC (rev 1016) @@ -2,6 +2,9 @@
geanyplugins_LTLIBRARIES = codenav.la
-codenav_la_SOURCES = codenavigation.c +codenav_la_SOURCES = \ + codenavigation.c \ + switch_head_impl.c + codenav_la_LIBADD = $(COMMONLIBS)
Modified: trunk/geany-plugins/codenav/src/codenavigation.c =================================================================== --- trunk/geany-plugins/codenav/src/codenavigation.c 2009-10-18 13:14:05 UTC (rev 1015) +++ trunk/geany-plugins/codenav/src/codenavigation.c 2009-10-18 13:17:02 UTC (rev 1016) @@ -1,8 +1,8 @@ /* - * codenavigation.c - this file is part of Geany, a fast and lightweight IDE + * codenavigation.c - this file is part of "codenavigation", which is + * part of the "geany-plugins" project. * - * Copyright 2007-2009 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de> - * Copyright 2007-2009 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com> + * Copyright 2009 Lionel Fuentes <funto66(at)gmail(dot)com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,8 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * $Id: codenavigation.c 3522 2009-01-28 17:55:58Z eht16 $ */
/** @@ -27,40 +25,19 @@ * 2009 Lionel Fuentes. */
-/* First */ -#include "geany.h" /* for the GeanyApp data type */ +#include "codenavigation.h" +#include "switch_head_impl.h" +#include "goto_file.h"
-/* Other includes */ -#include "support.h" /* for the _() translation macro (see also po/POTFILES.in) */ -#include "editor.h" /* for the declaration of the GeanyEditor struct, not strictly necessary - as it will be also included by plugindata.h */ -#include "document.h" /* for the declaration of the GeanyDocument struct */ -#include "ui_utils.h" -#include "Scintilla.h" /* for the SCNotification struct */ +/************************* Global variables ***************************/
-#include "keybindings.h" -#include "filetypes.h" -#include <gdk/gdkkeysyms.h> -#include <string.h> +static GtkWidget* edit_menu_item_separator = NULL;
-/* Last */ -#include "plugindata.h" /* this defines the plugin API */ -#include "geanyfunctions.h" /* this wraps geany_functions function pointers */ - /* These items are set by Geany before plugin_init() is called. */ GeanyPlugin *geany_plugin; GeanyData *geany_data; GeanyFunctions *geany_functions;
-//#define CODE_NAVIGATION_DEBUG -#define CODE_NAVIGATION_VERSION "0.1" - -#ifdef CODE_NAVIGATION_DEBUG -#define log_debug g_print -#else -static void log_debug(const gchar* s, ...) {} -#endif - /* Check that the running Geany supports the plugin API used below, and check * for binary compatibility. */ PLUGIN_VERSION_CHECK(112) @@ -72,653 +49,116 @@ "- switching between a .cpp file and the corresponding .h file\n" "- [opening a file by typing its name -> TODO]"), CODE_NAVIGATION_VERSION, _("Lionel Fuentes"))
-static GtkWidget* switch_menu_item = NULL; -static GtkWidget* goto_file_menu_item = NULL; -static GtkWidget* file_menu_item_separator = NULL; +/* Declare "GeanyKeyGroupInfo plugin_key_group_info[1]" and "GeanyKeyGroup *plugin_key_group", + * for Geany to find the keybindings */ +PLUGIN_KEY_GROUP(code_navigation, NB_KEY_IDS)
-typedef struct -{ - const gchar* language_name; - GSList* head_extensions; /* e.g. : "h", "hpp", ... */ - GSList* impl_extensions; /* e.g. : "cpp", "cxx", ... */ -} LanguageExtensions; +/***************************** Functions ******************************/
-/* List of LanguageExtensions */ -static GSList* languages_extensions; +static void +on_configure_response(GtkDialog *dialog, gint response, gpointer user_data);
-/* Keybindings */ -enum +/* --------------------------------------------------------------------- + * Called by Geany to initialize the plugin. + * Note: data is the same as geany_data. + * --------------------------------------------------------------------- + */ +void plugin_init(GeanyData *data) { - PLUGIN_KEYS_SWITCH, - PLUGIN_KEYS_GOTO_FILE, - PLUGIN_KEYS_NUMBER /* Dummy value, just to keep track of the number of different values */ -}; + GtkWidget* edit_menu = ui_lookup_widget(geany->main_widgets->window, "edit1_menu");
-PLUGIN_KEY_GROUP(code_navigation, PLUGIN_KEYS_NUMBER) + log_func();
-#if !GLIB_CHECK_VERSION(2, 16, 0) -int -g_strcmp0(const char *str1, const char *str2) -{ - if (!str1) - return -(str1 != str2); - if (!str2) - return str1 != str2; - return strcmp(str1, str2); -} -#endif + /* Add a separator to the "Edit" menu : */ + edit_menu_item_separator = gtk_separator_menu_item_new(); + gtk_container_add(GTK_CONTAINER(edit_menu), edit_menu_item_separator);
-/* Utility function, which returns a newly-allocated string containing the - * extension of the file path which is given, or NULL if it did not found any extension. - */ -static gchar* -get_extension(gchar* path) -{ - gchar* extension = NULL; - gchar* pc = path; - while(*pc != '\0') - { - if(*pc == '.') - extension = pc+1; - pc++; - } - - if(extension == NULL || (*extension) == '\0') - return NULL; - else - return g_strdup(extension); + /* Initialize the features */ + switch_head_impl_init(); + goto_file_init(); }
-/* Copy a path and remove the extension +/* --------------------------------------------------------------------- + * Called by Geany to show the plugin's configure dialog. This function + * is always called after plugin_init() is called. + * --------------------------------------------------------------------- */ -static gchar* -copy_and_remove_extension(gchar* path) +GtkWidget *plugin_configure(GtkDialog *dialog) { - gchar* str = NULL; - gchar* pc = NULL; - gchar* dot_pos = NULL; + log_func();
- if(path == NULL || path[0] == '\0') - return NULL; + GtkWidget *vbox;
- str = g_strdup(path); - pc = str; - while(*pc != '\0') - { - if(*pc == '.') - dot_pos = pc; - pc++; - } + vbox = gtk_vbox_new(FALSE, 6);
- if(dot_pos != NULL) - *dot_pos = '\0'; + /* Switch header/implementation widget */ + gtk_box_pack_start(GTK_BOX(vbox), switch_head_impl_config_widget(), TRUE, TRUE, 0);
- return str; -} + gtk_widget_show_all(vbox);
-/* Callback when the menu item is clicked. */ -static void -switch_menu_item_activate(guint key_id) -{ - GeanyDocument* current_doc = document_get_current(); - GeanyDocument* new_doc = NULL; - guint nb_documents = geany->documents_array->len; + /* Connect a callback for when the user clicks a dialog button */ + g_signal_connect(dialog, "response", G_CALLBACK(on_configure_response), NULL);
- gchar* extension = NULL; /* e.g. : "hpp" */ - - GSList* p_extensions_to_test = NULL; /* e.g. : ["cpp", "cxx", ...] */ - - GSList* filenames_to_test = NULL; /* e.g. : ["f.cpp", "f.cxx", ...] */ - - GSList* p_lang = NULL; - GSList* p_ext = NULL; - GSList* p_filename = NULL; - gint i=0; - - gchar* dirname = NULL; - gchar* basename = NULL; - gchar* basename_no_extension = NULL; - - gchar* p_str = NULL; /* Local variables, used as temporaty buffers */ - gchar* p_str2 = NULL; - - log_debug("DEBUG : switch menu activate\n"); - - log_debug("DEBUG : current_doc->file_name == %s\n", current_doc->file_name); - - log_debug("DEBUG : geany->documents_array->len == %d\n", geany->documents_array->len); - - if(current_doc != NULL && current_doc->file_name != NULL && current_doc->file_name[0] != '\0') - { - /* Get the basename, e.g. : "/home/me/file.cpp" -> "file.cpp" */ - basename = g_path_get_basename(current_doc->file_name); - - if(g_utf8_strlen(basename, -1) < 2) - goto free_mem; - - log_debug("DEBUG : basename == %s\n", basename); - - /* Get the extension , e.g. : "cpp" */ - extension = get_extension(basename); - - if(extension == NULL || g_utf8_strlen(extension, -1) == 0) - goto free_mem; - - log_debug("DEBUG : extension == %s\n", extension); - - /* Get the basename without any extension */ - basename_no_extension = copy_and_remove_extension(basename); - if(basename_no_extension == NULL || g_utf8_strlen(basename_no_extension, -1) == 0) - goto free_mem; - - /* Identify the language and whether the file is a header or an implementation. */ - /* For each recognized language : */ - for(p_lang = languages_extensions ; p_lang != NULL ; p_lang = p_lang->next) - { - LanguageExtensions* p_lang_data = (LanguageExtensions*)(p_lang->data); - - /* Test the headers : */ - if(g_slist_find_custom(p_lang_data->head_extensions, extension, (GCompareFunc)(&g_strcmp0)) != NULL) - { - p_extensions_to_test = p_lang_data->impl_extensions; - break; - } - - /* Test the implementations : */ - else if(g_slist_find_custom(p_lang_data->impl_extensions, extension, (GCompareFunc)(&g_strcmp0)) != NULL) - { - p_extensions_to_test = p_lang_data->head_extensions; - break; - } - } - - if(p_extensions_to_test == NULL) - goto free_mem; - -#ifdef CODE_NAVIGATION_DEBUG - log_debug("DEBUG : extension known !\n"); - log_debug("DEBUG : p_extensions_to_test : "); - g_slist_foreach(p_extensions_to_test, (GFunc)(&log_debug), NULL); - log_debug("\n"); -#endif - - /* Build a list of filenames to test : */ - filenames_to_test = NULL; - for(p_ext = p_extensions_to_test ; p_ext != NULL ; p_ext = p_ext->next) - { - p_str = g_strdup_printf("%s.%s", basename_no_extension, (const gchar*)(p_ext->data)); - filenames_to_test = g_slist_prepend(filenames_to_test, p_str); - } - - filenames_to_test = g_slist_reverse(filenames_to_test); - -#ifdef CODE_NAVIGATION_DEBUG - log_debug("DEBUG : filenames to test :\n"); - g_slist_foreach(filenames_to_test, (GFunc)(&log_debug), NULL); - log_debug("\n"); -#endif - - /* First : look for a corresponding file in the opened files. - * If found, open it. */ - for(i=0 ; i < nb_documents ; i++) - { - new_doc = document_index(i); - - for(p_filename = filenames_to_test ; p_filename != NULL ; p_filename = p_filename->next) - { - p_str = g_path_get_basename(new_doc->file_name); - - log_debug("DEBUG : comparing "%s" and "%s"\n", (const gchar*)(p_filename->data), p_str); - if(g_strcmp0((const gchar*)(p_filename->data), p_str) == 0) - { - log_debug("DEBUG : FOUND !\n"); - g_free(p_str); - - p_str = g_locale_from_utf8(new_doc->file_name, -1, NULL, NULL, NULL); - document_open_file(p_str, FALSE, NULL, NULL); - g_free(p_str); - goto free_mem; - } - - g_free(p_str); - } - } - - - /* Second : if not found, look for a corresponding file in the same directory. - * If found, open it. - */ - /* -> compute dirname */ - dirname = g_path_get_dirname(current_doc->real_path); - if(dirname == NULL) - goto free_mem; - - log_debug("DEBUG : dirname == "%s"", dirname); - - /* -> try all the extensions we should test */ - for(p_ext = p_extensions_to_test ; p_ext != NULL ; p_ext = p_ext->next) - { - p_str = g_strdup_printf( "%s" G_DIR_SEPARATOR_S "%s.%s", - dirname, basename_no_extension, (const gchar*)(p_ext->data)); - - p_str2 = g_locale_from_utf8(p_str, -1, NULL, NULL, NULL); - g_free(p_str); - - log_debug("DEBUG : trying to open the file "%s"\n", p_str2); - - /* Try without read-only and in read-only mode */ - if( document_open_file(p_str2, FALSE, NULL, NULL) != NULL || - document_open_file(p_str2, TRUE, NULL, NULL) != NULL) - { - g_free(p_str2); - goto free_mem; - } - g_free(p_str2); - } - - /* Third : if not found, ask the user if he wants to create it or not. */ - { - GtkWidget* dialog; - - p_str = g_strdup_printf("%s.%s", basename_no_extension, (const gchar*)(p_extensions_to_test->data)); - - dialog = gtk_message_dialog_new( GTK_WINDOW(geany_data->main_widgets->window), - GTK_DIALOG_MODAL, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_OK_CANCEL, - _("%s not found, create it ?"), p_str); - gtk_window_set_title(GTK_WINDOW(dialog), "Geany"); - if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) - { - document_new_file(p_str, current_doc->file_type, NULL); - document_set_text_changed(document_get_current(), TRUE); - } - - log_debug("DESTROY"); - - gtk_widget_destroy(dialog); - - g_free(p_str); - } - - /* Free the memory */ -free_mem: - g_slist_foreach(filenames_to_test, (GFunc)(&g_free), NULL); - g_free(dirname); - g_free(basename_no_extension); - g_free(extension); - g_free(basename); - } + return vbox; }
-/* Callback when the menu item is clicked. */ -static void -goto_file_menu_item_activate(guint key_id) +/* --------------------------------------------------------------------- + * Called by Geany before unloading the plugin. + * --------------------------------------------------------------------- + */ +void plugin_cleanup(void) { - GtkWidget *dialog; - - dialog = gtk_message_dialog_new( - GTK_WINDOW(geany->main_widgets->window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_INFO, - GTK_BUTTONS_OK, - "Open by name : TODO"); - - gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), - _("(From the %s plugin)"), geany_plugin->info->name); - - gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); -} - - -/* Called by Geany to initialize the plugin. - * Note: data is the same as geany_data. */ -void plugin_init(GeanyData *data) -{ - LanguageExtensions* le = NULL; - - gchar* p_str = NULL; - - /* Get a pointer to the "Edit" menu */ GtkWidget* edit_menu = ui_lookup_widget(geany->main_widgets->window, "edit1_menu");
- log_debug("DEBUG : plugin_init\n"); + log_func();
- /* Add items to the Edit menu : */ + /* Cleanup the features */ + goto_file_cleanup(); + switch_head_impl_cleanup();
- /* - add a separator */ - file_menu_item_separator = gtk_separator_menu_item_new(); - gtk_container_add(GTK_CONTAINER(edit_menu), file_menu_item_separator); - gtk_widget_show(file_menu_item_separator); - - /* - add the "Switch header/implementation" menu item */ - switch_menu_item = gtk_menu_item_new_with_mnemonic(_("Switch header/implementation")); - gtk_widget_show(switch_menu_item); - gtk_container_add(GTK_CONTAINER(edit_menu), switch_menu_item); - - /* - add the "Open file by name" menu item */ - goto_file_menu_item = gtk_menu_item_new_with_mnemonic(_("Goto file...")); - gtk_widget_show(goto_file_menu_item); - gtk_container_add(GTK_CONTAINER(edit_menu), goto_file_menu_item); - - /* make the menu items sensitive only when documents are open */ - ui_add_document_sensitive(switch_menu_item); - ui_add_document_sensitive(goto_file_menu_item); - - /* Initialize the key bindings : */ - keybindings_set_item( plugin_key_group, - PLUGIN_KEYS_SWITCH, - (GeanyKeyCallback)(&switch_menu_item_activate), - GDK_s, GDK_MOD1_MASK | GDK_SHIFT_MASK, - _("switch_header_impl"), - _("Switch header/implementation"), - switch_menu_item); - - keybindings_set_item( plugin_key_group, - PLUGIN_KEYS_GOTO_FILE, - (GeanyKeyCallback)(&goto_file_menu_item_activate), - GDK_g, GDK_MOD1_MASK | GDK_SHIFT_MASK, - _("goto_file"), - _("Goto file..."), - goto_file_menu_item); - - /* Initialize the extensions list. - * TODO : we should let the user configure this. */ - languages_extensions = NULL; - le = NULL; - -#define HEAD_PREPEND(str_ext) { p_str = g_strdup(str_ext); le->head_extensions = g_slist_prepend(le->head_extensions, p_str); } -#define IMPL_PREPEND(str_ext) { p_str = g_strdup(str_ext); le->impl_extensions = g_slist_prepend(le->impl_extensions, p_str); } - - /* C/C++ */ - le = g_malloc0(sizeof(LanguageExtensions)); - le->language_name = "c_cpp"; - - HEAD_PREPEND("h"); - HEAD_PREPEND("hpp"); - HEAD_PREPEND("hxx"); - HEAD_PREPEND("h++"); - HEAD_PREPEND("hh"); - le->head_extensions = g_slist_reverse(le->head_extensions); - - IMPL_PREPEND("cpp"); - IMPL_PREPEND("cxx"); - IMPL_PREPEND("c++"); - IMPL_PREPEND("cc"); - IMPL_PREPEND("C"); - IMPL_PREPEND("c"); - le->impl_extensions = g_slist_reverse(le->impl_extensions); - - languages_extensions = g_slist_prepend(languages_extensions, le); - - /* GLSL */ - - le = g_malloc0(sizeof(LanguageExtensions)); - le->language_name = "glsl"; - - HEAD_PREPEND("vert"); - le->head_extensions = g_slist_reverse(le->head_extensions); - - IMPL_PREPEND("frag"); - le->impl_extensions = g_slist_reverse(le->impl_extensions); - - languages_extensions = g_slist_prepend(languages_extensions, le); - - /* Ada */ - - le = g_malloc0(sizeof(LanguageExtensions)); - le->language_name = "ada"; - - HEAD_PREPEND("ads"); - le->head_extensions = g_slist_reverse(le->head_extensions); - - IMPL_PREPEND("adb"); - le->impl_extensions = g_slist_reverse(le->impl_extensions); - - languages_extensions = g_slist_prepend(languages_extensions, le); - - /* Done : */ - languages_extensions = g_slist_reverse(languages_extensions); - -#undef HEAD_PREPEND -#undef IMPL_PREPEND + /* Remove the separator in the "Edit" menu */ + gtk_widget_destroy(edit_menu_item_separator); }
- -/* Callback connected in plugin_configure(). */ +/* --------------------------------------------------------------------- + * Callback called when validating the configuration of the plug-in + * --------------------------------------------------------------------- + */ static void -on_configure_response(GtkDialog *dialog, gint response, gpointer user_data) +on_configure_response(GtkDialog* dialog, gint response, gpointer user_data) { - /* catch OK or Apply clicked */ - if (response == GTK_RESPONSE_OK || response == GTK_RESPONSE_APPLY) + /* TODO */ +#if 0 + GKeyFile* key_file = NULL; + gchar* config_dir = NULL; + gchar* config_filename = NULL; + + if(response == GTK_RESPONSE_OK || response == GTK_RESPONSE_APPLY) { - /* maybe the plugin should write here the settings into a file - * (e.g. using GLib's GKeyFile API) - * all plugin specific files should be created in: - * geany->app->configdir G_DIR_SEPARATOR_S plugins G_DIR_SEPARATOR_S pluginname G_DIR_SEPARATOR_S - * e.g. this could be: ~/.config/geany/plugins/Demo/, please use geany->app->configdir */ + /* Write the settings into a file, using GLib's GKeyFile API. + * File name : + * geany->app->configdir G_DIR_SEPARATOR_S "plugins" G_DIR_SEPARATOR_S "codenav" G_DIR_SEPARATOR_S "codenav.conf" + * e.g. this could be: ~/.config/geany/plugins/codenav/codenav.conf + */
- const gchar** lang_names = NULL; - GSList* lang_iterator = NULL; - guint i=0; - const guint nb_languages = g_slist_length(languages_extensions); - /* Open the GKeyFile */ - GKeyFile* key_file = g_key_file_new(); - gchar* config_dir = g_strconcat(geany->app->configdir, G_DIR_SEPARATOR_S "plugins" G_DIR_SEPARATOR_S - "codenav" G_DIR_SEPARATOR_S, NULL); - gchar* config_filename = g_strconcat(config_dir, "codenav.conf", NULL); + key_file = g_key_file_new();
- g_key_file_load_from_file(key_file, config_filename, G_KEY_FILE_NONE, NULL); + config_dir = g_strconcat(geany->app->configdir, + G_DIR_SEPARATOR_S "plugins" G_DIR_SEPARATOR_S "codenav" G_DIR_SEPARATOR_S, NULL);
- /* Build an array of language names */ - lang_names = g_malloc(nb_languages * sizeof(gchar*)); - for(lang_iterator = languages_extensions, i=0 ; - lang_iterator != NULL ; - lang_iterator = lang_iterator->next, i++) - { - lang_names[i] = ((const LanguageExtensions*)(lang_iterator->data))->language_name; - } + config_filename = g_strconcat(config_dir, "codenav.conf", NULL);
- g_key_file_set_string_list(key_file, "switching", "languages", lang_names, nb_languages); + /* Load configuration */ + g_key_file_load_from_file(key_file, config_filename, G_KEY_FILE_NONE, NULL);
- g_free(lang_names); + /* Write configuration */ + write_switch_head_impl_config(key_file);
- /* Finally write to the config file */ - if (!g_file_test(config_dir, G_FILE_TEST_IS_DIR) - && utils_mkdir(config_dir, TRUE) != 0) - { - dialogs_show_msgbox(GTK_MESSAGE_ERROR, _("Plugin configuration directory could not be created.")); - } - else - { - gchar* data = g_key_file_to_data(key_file, NULL, NULL); - utils_write_file(config_filename, data); - g_free(data); - } - - g_free(config_dir); + /* Cleanup */ g_free(config_filename); + g_free(config_dir); g_key_file_free(key_file); } +#endif } - -/* Callback connected in plugin_configure() to the click on the "Add" button for the - * "Switch headers/implementation" frame */ -static void -on_configure_add_language(GtkWidget* widget, gpointer data) -{ - GtkWidget *list_view = (GtkWidget*)data; - GtkListStore *list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list_view))); - GtkTreeIter iter; - GtkTreePath *path; - GtkTreeViewColumn* column = NULL; - gint nb_lines; - - /* Add a line */ - gtk_list_store_append(list_store, &iter); - - /* and give the focus to it */ - nb_lines = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(list_store), NULL); - - path = gtk_tree_path_new_from_indices(nb_lines-1, -1); - - column = gtk_tree_view_get_column(GTK_TREE_VIEW(list_view), 0); - gtk_tree_view_set_cursor(GTK_TREE_VIEW(list_view), path, column, TRUE); - gtk_widget_grab_focus(list_view); - - gtk_tree_path_free(path); -} - -/* Same thing for the "Remove" button */ -static void -on_configure_remove_language(GtkWidget* widget, gpointer data) -{ - //GtkWidget* list_view = (GtkWidget*)data; -} - -/* Called by Geany to show the plugin's configure dialog. This function is always called after - * plugin_init() was called. - */ -GtkWidget *plugin_configure(GtkDialog *dialog) -{ - GtkWidget *label, *vbox, *list_view, *switch_frame_vbox; - GtkWidget *switch_frame, *switch_frame_hbox, *add_button, *remove_button; - GtkListStore *list_store; - GtkTreeViewColumn *column; - GtkCellRenderer *cell_renderer; - GtkTreeIter iter; - GSList* p_le = NULL; - gchar* p_str = NULL; - gint i=0; - - typedef enum { COLUMN_HEAD, COLUMN_IMPL, NB_COLUMNS } Column; - - vbox = gtk_vbox_new(FALSE, 6); - - /* Add a label */ - label = gtk_label_new(_("Code Navigation plug-in configuration")); - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0); - - /* Add a frame for the switch header/implementation feature */ - switch_frame = gtk_frame_new(_("Switch header / implementation")); - gtk_box_pack_start(GTK_BOX(vbox), switch_frame, FALSE, TRUE, 0); - - /* Add a vbox into the frame */ - switch_frame_vbox = gtk_vbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(switch_frame), switch_frame_vbox); - - /* Add a list containing the extensions for each language (headers / implementations) */ - /* - create the GtkListStore */ - list_store = gtk_list_store_new(NB_COLUMNS, G_TYPE_STRING, G_TYPE_STRING); - for(p_le = languages_extensions ; p_le != NULL ; p_le = p_le->next) - { - LanguageExtensions* le = (LanguageExtensions*)(p_le->data); - GSList* p_extensions = NULL; - GSList* p_ext = NULL; - Column col; - - if(le->head_extensions == NULL || le->impl_extensions == NULL) - continue; - - /* Fill the GtkListStore with comma-separated strings */ - /* loop : "headers", then "implementations" */ - col = COLUMN_HEAD; - p_extensions = le->head_extensions; - for(i=0 ; i<2 ; i++) - { - /* Copy extensions to str_array and then join the strings, separated with commas. */ - p_str = NULL; - for(p_ext = p_extensions ; p_ext != NULL ; p_ext = p_ext->next) - { - gchar* temp = p_str; - p_str = g_strjoin(",", (const gchar*)(p_ext->data), p_str, NULL); - g_free(temp); - } - log_debug("DEBUG : str == "%s"", p_str); - - if(i == 0) - gtk_list_store_append(list_store, &iter); - gtk_list_store_set(list_store, &iter, col, p_str, -1); - - g_free(p_str); - - /* Next iteration : "implementations" */ - col = COLUMN_IMPL; - p_extensions = le->impl_extensions; - } - } - - /* - create the GtkTreeView */ - list_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store)); - - /* - add the columns */ - /* -> headers : */ - cell_renderer = gtk_cell_renderer_text_new(); - g_object_set(G_OBJECT(cell_renderer), "editable", TRUE, NULL); - column = gtk_tree_view_column_new_with_attributes( _("Headers extensions"), cell_renderer, - "text", COLUMN_HEAD, - NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column); - - /* -> implementations : */ - cell_renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes( _("Implementations extensions"), cell_renderer, - "text", COLUMN_IMPL, - NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column); - - /* - finally add the GtkTreeView to the frame's vbox */ - gtk_box_pack_start(GTK_BOX(switch_frame_vbox), list_view, FALSE, TRUE, 0); - - /* Add an hbox for the frame's button(s) */ - switch_frame_hbox = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(switch_frame_vbox), switch_frame_hbox, FALSE, FALSE, 0); - - /* Add the "add" button to the frame's hbox */ - add_button = gtk_button_new_from_stock(GTK_STOCK_ADD); - g_signal_connect(G_OBJECT(add_button), "clicked", G_CALLBACK(on_configure_add_language), list_view); - gtk_box_pack_start(GTK_BOX(switch_frame_hbox), add_button, FALSE, FALSE, 0); - - /* Add the "remove" button to the frame's hbox */ - remove_button = gtk_button_new_from_stock(GTK_STOCK_REMOVE); - g_signal_connect(G_OBJECT(remove_button), "clicked", G_CALLBACK(on_configure_remove_language), list_view); - gtk_box_pack_start(GTK_BOX(switch_frame_hbox), remove_button, FALSE, FALSE, 0); - - /* Show all */ - gtk_widget_show_all(vbox); - - /* Connect a callback for when the user clicks a dialog button */ - g_signal_connect(dialog, "response", G_CALLBACK(on_configure_response), NULL); - return vbox; -} - - -/* Called by Geany before unloading the plugin. - * Here any UI changes should be removed, memory freed and any other finalization done. - * Be sure to leave Geany as it was before plugin_init(). */ -void plugin_cleanup(void) -{ - GSList* p_le = NULL; - - log_debug("DEBUG : plugin_cleanup\n"); - - for(p_le = languages_extensions ; p_le != NULL ; p_le = p_le->next) - { - LanguageExtensions* le = (LanguageExtensions*)(p_le->data); - - g_slist_foreach(le->head_extensions, (GFunc)(&g_free), NULL); - g_slist_free(le->head_extensions); - - g_slist_foreach(le->impl_extensions, (GFunc)(&g_free), NULL); - g_slist_free(le->impl_extensions); - } - - g_slist_free(languages_extensions); - - /* remove the menu item added in plugin_init() */ - gtk_widget_destroy(switch_menu_item); - gtk_widget_destroy(goto_file_menu_item); - gtk_widget_destroy(file_menu_item_separator); -}
Added: trunk/geany-plugins/codenav/src/codenavigation.h =================================================================== --- trunk/geany-plugins/codenav/src/codenavigation.h (rev 0) +++ trunk/geany-plugins/codenav/src/codenavigation.h 2009-10-18 13:17:02 UTC (rev 1016) @@ -0,0 +1,87 @@ +/* + * codenavigation.h - this file is part of "codenavigation", which is + * part of the "geany-plugins" project. + * + * Copyright 2009 Lionel Fuentes <funto66(at)gmail(dot)com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef CODENAVIGATION_H +#define CODENAVIGATION_H + +/* First */ +#include "geany.h" /* for the GeanyApp data type */ + +/* Other includes */ +#include "support.h" /* for the _() translation macro (see also po/POTFILES.in) */ +#include "editor.h" /* for the declaration of the GeanyEditor struct, not strictly necessary + as it will be also included by plugindata.h */ +#include "document.h" /* for the declaration of the GeanyDocument struct */ +#include "ui_utils.h" +#include "Scintilla.h" /* for the SCNotification struct */ + +#include "keybindings.h" +#include "filetypes.h" +#include <gdk/gdkkeysyms.h> +#include <string.h> + +#include "switch_head_impl.h" + +/* Last */ +#include "plugindata.h" /* this defines the plugin API */ +#include "geanyfunctions.h" /* this wraps geany_functions function pointers */ + +/* Debug flag */ +#define CODE_NAVIGATION_DEBUG + +#define CODE_NAVIGATION_VERSION "0.1" + +/* Log utilities */ +#ifdef CODE_NAVIGATION_DEBUG +static void log_debug(const gchar* s, ...) +{ + gchar* format = g_strconcat("[CODENAV DEBUG] : ", s, "\n", NULL); + va_list l; + va_start(l, s); + g_vprintf(format, l); + g_free(format); + va_end(l); +} + +#define log_func() g_print("[CODENAV FUNC] : %s", __func__) /* NB : this needs the C99 standard, but is only + used when debugging, so no problem :) */ +#else +static void log_debug(const gchar* s, ...) {} +static void log_func() {} +#endif + +/* IDs for keybindings */ +enum +{ + KEY_ID_SWITCH_HEAD_IMPL, + KEY_ID_GOTO_FILE, + NB_KEY_IDS +}; + +/* Items for controlling geany */ +extern GeanyPlugin *geany_plugin; +extern GeanyData *geany_data; +extern GeanyFunctions *geany_functions; + +extern GeanyKeyGroup *plugin_key_group; + +#endif /* CODENAVIGATION_H */
Added: trunk/geany-plugins/codenav/src/goto_file.c =================================================================== --- trunk/geany-plugins/codenav/src/goto_file.c (rev 0) +++ trunk/geany-plugins/codenav/src/goto_file.c 2009-10-18 13:17:02 UTC (rev 1016) @@ -0,0 +1,105 @@ +/* + * goto_file.c - this file is part of "codenavigation", which is + * part of the "geany-plugins" project. + * + * Copyright 2009 Lionel Fuentes <funto66(at)gmail(dot)com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "goto_file.h" + +/******************* Global variables for the feature *****************/ + +static GtkWidget* menu_item = NULL; + +/********************** Functions for the feature *********************/ + +/* --------------------------------------------------------------------- + * Callback when the menu item is clicked. + * --------------------------------------------------------------------- + */ +static void +menu_item_activate(guint key_id); + +/* --------------------------------------------------------------------- + * Initialization + * --------------------------------------------------------------------- + */ +void +goto_file_init() +{ + log_func(); + + GtkWidget* edit_menu = ui_lookup_widget(geany->main_widgets->window, "edit1_menu"); + + /* Add the menu item, sensitive only when a document is opened */ + menu_item = gtk_menu_item_new_with_mnemonic(_("Goto file")); + gtk_widget_show(menu_item); + gtk_container_add(GTK_CONTAINER(edit_menu), menu_item); + ui_add_document_sensitive(menu_item); + + /* Callback connection */ + g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(menu_item_activate), NULL); + + /* Initialize the key binding : */ + keybindings_set_item( plugin_key_group, + KEY_ID_GOTO_FILE, + (GeanyKeyCallback)(&menu_item_activate), + GDK_g, GDK_MOD1_MASK | GDK_SHIFT_MASK, + _("goto_file"), + _("Goto file"), /* used in the Preferences dialog */ + menu_item); +} + +/* --------------------------------------------------------------------- + * Cleanup + * --------------------------------------------------------------------- + */ +void +goto_file_cleanup() +{ + log_func(); + + gtk_widget_destroy(menu_item); +} + +/* --------------------------------------------------------------------- + * Callback when the menu item is clicked. + * --------------------------------------------------------------------- + */ +static void +menu_item_activate(guint key_id) +{ + log_func(); + + /* TODO */ + + GtkWidget *dialog = gtk_message_dialog_new( + GTK_WINDOW(geany->main_widgets->window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + "Open by name : TODO"); + + gtk_window_set_title(GTK_WINDOW(dialog), "Goto file..."); + + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), + _("(From the %s plugin)"), geany_plugin->info->name); + + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); +}
Added: trunk/geany-plugins/codenav/src/goto_file.h =================================================================== --- trunk/geany-plugins/codenav/src/goto_file.h (rev 0) +++ trunk/geany-plugins/codenav/src/goto_file.h 2009-10-18 13:17:02 UTC (rev 1016) @@ -0,0 +1,36 @@ +/* + * goto_file.h - this file is part of "codenavigation", which is + * part of the "geany-plugins" project. + * + * Copyright 2009 Lionel Fuentes <funto66(at)gmail(dot)com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef GOTO_FILE_H +#define GOTO_FILE_H + +#include "codenavigation.h" + +/* Initialization */ +void +goto_file_init(); + +/* Cleanup */ +void +goto_file_cleanup(); + +#endif /* GOTO_FILE_H */
Added: trunk/geany-plugins/codenav/src/switch_head_impl.c =================================================================== --- trunk/geany-plugins/codenav/src/switch_head_impl.c (rev 0) +++ trunk/geany-plugins/codenav/src/switch_head_impl.c 2009-10-18 13:17:02 UTC (rev 1016) @@ -0,0 +1,567 @@ +/* + * switch_head_impl.c - this file is part of "codenavigation", which is + * part of the "geany-plugins" project. + * + * Copyright 2009 Lionel Fuentes <funto66(at)gmail(dot)com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "switch_head_impl.h" +#include "utils.h" + +/********************* Data types for the feature *********************/ + +/* Structure representing a handled language */ +typedef struct +{ + const gchar* name; + GSList* head_extensions; /* e.g. : "h", "hpp", ... */ + GSList* impl_extensions; /* e.g. : "cpp", "cxx", ... */ +} Language; + +/* Column for the configuration widget */ +typedef enum +{ + COLUMN_HEAD, + COLUMN_IMPL, + NB_COLUMNS +} Column; + +/******************* Global variables for the feature *****************/ + +static GtkWidget* menu_item = NULL; +static GSList* languages = NULL; /* handled languages */ + +/********************** Functions for the feature *********************/ + +static void +fill_default_languages_list(); + +static void +menu_item_activate(guint key_id); + +static void +on_configure_add_language(GtkWidget* widget, gpointer data); + +static void +on_configure_remove_language(GtkWidget* widget, gpointer data); + +/* --------------------------------------------------------------------- + * Initialization + * --------------------------------------------------------------------- + */ +void +switch_head_impl_init() +{ + log_func(); + + GtkWidget* edit_menu = ui_lookup_widget(geany->main_widgets->window, "edit1_menu"); + + /* Add the menu item and make it sensitive only when a document is opened */ + menu_item = gtk_menu_item_new_with_mnemonic(_("Switch header/implementation")); + gtk_widget_show(menu_item); + gtk_container_add(GTK_CONTAINER(edit_menu), menu_item); + ui_add_document_sensitive(menu_item); + + /* Callback connection */ + g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(menu_item_activate), NULL); + + /* Initialize the key binding : */ + keybindings_set_item( plugin_key_group, + KEY_ID_SWITCH_HEAD_IMPL, + (GeanyKeyCallback)(&menu_item_activate), + GDK_s, GDK_MOD1_MASK | GDK_SHIFT_MASK, + _("switch_head_impl"), + _("Switch header/implementation"), /* used in the Preferences dialog */ + menu_item); + + /* TODO : we should use the languages specified by the user or the default list */ + fill_default_languages_list(); +} + +/* --------------------------------------------------------------------- + * Cleanup + * --------------------------------------------------------------------- + */ +void +switch_head_impl_cleanup() +{ + GSList* iter = NULL; + + log_func(); + + gtk_widget_destroy(menu_item); + + for(iter = languages ; iter != NULL ; iter = iter->next) + { + Language* lang = (Language*)(iter->data); + + g_slist_foreach(lang->head_extensions, (GFunc)(&g_free), NULL); /* free the data */ + g_slist_free(lang->head_extensions); /* free the list */ + + g_slist_foreach(lang->impl_extensions, (GFunc)(&g_free), NULL); + g_slist_free(lang->impl_extensions); + } + + g_slist_free(languages); +} + + +/* --------------------------------------------------------------------- + * Initialize the "languages" list to the default known languages + * --------------------------------------------------------------------- + */ +static void +fill_default_languages_list() +{ + Language* lang = g_malloc0(sizeof(Language)); + + languages = NULL; + +#define HEAD_PREPEND(str_ext) \ + { lang->head_extensions = g_slist_prepend(lang->head_extensions, g_strdup(str_ext)); } +#define IMPL_PREPEND(str_ext) \ + { lang->impl_extensions = g_slist_prepend(lang->impl_extensions, g_strdup(str_ext)); } + + /* C/C++ */ + lang = g_malloc0(sizeof(Language)); + lang->name = "c_cpp"; + + HEAD_PREPEND("h"); + HEAD_PREPEND("hpp"); + HEAD_PREPEND("hxx"); + HEAD_PREPEND("h++"); + HEAD_PREPEND("hh"); + lang->head_extensions = g_slist_reverse(lang->head_extensions); + + IMPL_PREPEND("cpp"); + IMPL_PREPEND("cxx"); + IMPL_PREPEND("c++"); + IMPL_PREPEND("cc"); + IMPL_PREPEND("C"); + IMPL_PREPEND("c"); + lang->impl_extensions = g_slist_reverse(lang->impl_extensions); + + languages = g_slist_prepend(languages, lang); + + /* GLSL */ + lang = g_malloc0(sizeof(Language)); + lang->name = "glsl"; + + HEAD_PREPEND("vert"); + lang->head_extensions = g_slist_reverse(lang->head_extensions); + + IMPL_PREPEND("frag"); + lang->impl_extensions = g_slist_reverse(lang->impl_extensions); + + languages = g_slist_prepend(languages, lang); + + /* Ada */ + lang = g_malloc0(sizeof(Language)); + lang->name = "ada"; + + HEAD_PREPEND("ads"); + lang->head_extensions = g_slist_reverse(lang->head_extensions); + + IMPL_PREPEND("adb"); + lang->impl_extensions = g_slist_reverse(lang->impl_extensions); + + languages = g_slist_prepend(languages, lang); + + /* Done : */ + languages = g_slist_reverse(languages); + +#undef HEAD_PREPEND +#undef IMPL_PREPEND +} + +/* --------------------------------------------------------------------- + * Callback when the menu item is clicked. + * --------------------------------------------------------------------- + */ +static void +menu_item_activate(guint key_id) +{ + GeanyDocument* current_doc = document_get_current(); + GeanyDocument* new_doc = NULL; + guint nb_documents = geany->documents_array->len; + + gchar* extension = NULL; /* e.g. : "hpp" */ + + GSList* p_extensions_to_test = NULL; /* e.g. : ["cpp", "cxx", ...] */ + + GSList* filenames_to_test = NULL; /* e.g. : ["f.cpp", "f.cxx", ...] */ + + GSList* iter_lang = NULL; + GSList* iter_ext = NULL; + GSList* iter_filename = NULL; + gint i=0; + + gchar* dirname = NULL; + gchar* basename = NULL; + gchar* basename_no_extension = NULL; + + gchar* p_str = NULL; /* Local variables, used as temporary buffers */ + gchar* p_str2 = NULL; + + log_func(); + log_debug("current_doc->file_name == %s", current_doc->file_name); + log_debug("geany->documents_array->len == %d", geany->documents_array->len); + + if(current_doc != NULL && current_doc->file_name != NULL && current_doc->file_name[0] != '\0') + { + /* Get the basename, e.g. : "/home/me/file.cpp" -> "file.cpp" */ + basename = g_path_get_basename(current_doc->file_name); + + if(g_utf8_strlen(basename, -1) < 2) + goto free_mem; + + log_debug("basename == %s", basename); + + /* Get the extension , e.g. : "cpp" */ + extension = get_extension(basename); + + if(extension == NULL || g_utf8_strlen(extension, -1) == 0) + goto free_mem; + + log_debug("extension == %s", extension); + + /* Get the basename without any extension */ + basename_no_extension = copy_and_remove_extension(basename); + if(basename_no_extension == NULL || g_utf8_strlen(basename_no_extension, -1) == 0) + goto free_mem; + + /* Identify the language and whether the file is a header or an implementation. */ + /* For each recognized language : */ + for(iter_lang = languages ; iter_lang != NULL ; iter_lang = iter_lang->next) + { + Language* lang = (Language*)(iter_lang->data); + + /* Test the headers : */ + if(g_slist_find_custom(lang->head_extensions, extension, (GCompareFunc)(&compare_strings)) != NULL) + { + p_extensions_to_test = lang->impl_extensions; + break; + } + + /* Test the implementations : */ + else if(g_slist_find_custom(lang->impl_extensions, extension, (GCompareFunc)(&compare_strings)) != NULL) + { + p_extensions_to_test = lang->head_extensions; + break; + } + } + + if(p_extensions_to_test == NULL) + goto free_mem; + +#ifdef CODE_NAVIGATION_DEBUG + log_debug("extension known !"); + log_debug("p_extensions_to_test : "); + g_slist_foreach(p_extensions_to_test, (GFunc)(&log_debug), NULL); +#endif + + /* Build a list of filenames to test : */ + filenames_to_test = NULL; + for(iter_ext = p_extensions_to_test ; iter_ext != NULL ; iter_ext = iter_ext->next) + { + p_str = g_strdup_printf("%s.%s", basename_no_extension, (const gchar*)(iter_ext->data)); + filenames_to_test = g_slist_prepend(filenames_to_test, p_str); + } + + filenames_to_test = g_slist_reverse(filenames_to_test); + +#ifdef CODE_NAVIGATION_DEBUG + log_debug("filenames to test :"); + g_slist_foreach(filenames_to_test, (GFunc)(&log_debug), NULL); +#endif + + /* First : look for a corresponding file in the opened files. + * If found, open it. */ + for(i=0 ; i < nb_documents ; i++) + { + new_doc = document_index(i); + + for(iter_filename = filenames_to_test ; iter_filename != NULL ; iter_filename = iter_filename->next) + { + p_str = g_path_get_basename(new_doc->file_name); + + log_debug("comparing "%s" and "%s"", (const gchar*)(iter_filename->data), p_str); + if(utils_str_equal((const gchar*)(iter_filename->data), p_str)) + { + log_debug("FOUND !"); + g_free(p_str); + + p_str = g_locale_from_utf8(new_doc->file_name, -1, NULL, NULL, NULL); + document_open_file(p_str, FALSE, NULL, NULL); + g_free(p_str); + goto free_mem; + } + g_free(p_str); + } + } + + /* Second : if not found, look for a corresponding file in the same directory. + * If found, open it. + */ + /* -> compute dirname */ + dirname = g_path_get_dirname(current_doc->real_path); + if(dirname == NULL) + goto free_mem; + + log_debug("dirname == "%s"", dirname); + + /* -> try all the extensions we should test */ + for(iter_ext = p_extensions_to_test ; iter_ext != NULL ; iter_ext = iter_ext->next) + { + p_str = g_strdup_printf( "%s" G_DIR_SEPARATOR_S "%s.%s", + dirname, basename_no_extension, (const gchar*)(iter_ext->data)); + + p_str2 = g_locale_from_utf8(p_str, -1, NULL, NULL, NULL); + g_free(p_str); + + log_debug("trying to open the file "%s"\n", p_str2); + + /* Try without read-only and in read-only mode */ + if( document_open_file(p_str2, FALSE, NULL, NULL) != NULL || + document_open_file(p_str2, TRUE, NULL, NULL) != NULL) + { + g_free(p_str2); + goto free_mem; + } + g_free(p_str2); + } + + /* Third : if not found, ask the user if he wants to create it or not. */ + { + p_str = g_strdup_printf("%s.%s", basename_no_extension, (const gchar*)(p_extensions_to_test->data)); + + GtkWidget* dialog = gtk_message_dialog_new( GTK_WINDOW(geany_data->main_widgets->window), + GTK_DIALOG_MODAL, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_OK_CANCEL, + _("%s not found, create it ?"), p_str); + gtk_window_set_title(GTK_WINDOW(dialog), "Geany"); + if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) + { + document_new_file(p_str, current_doc->file_type, NULL); + document_set_text_changed(document_get_current(), TRUE); + } + + log_debug("DESTROY"); + + gtk_widget_destroy(dialog); + + g_free(p_str); + } + + /* Free the memory */ +free_mem: + g_slist_foreach(filenames_to_test, (GFunc)(&g_free), NULL); + g_free(dirname); + g_free(basename_no_extension); + g_free(extension); + g_free(basename); + } +} + +/* --------------------------------------------------------------------- + * Configuration widget + * --------------------------------------------------------------------- + */ + +/* ----- Utility function to concatenate the extensions of a ----- + * language, separated with a comma. */ +static gchar* +concatenate_extensions(GSList* extensions) +{ + GSList* iter_ext; + gchar* p_str = NULL; + gchar* temp = NULL; + + for(iter_ext = extensions ; iter_ext != NULL ; iter_ext = iter_ext->next) + { + temp = p_str; + p_str = g_strjoin(",", (const gchar*)(iter_ext->data), p_str, NULL); + g_free(temp); + } + + return p_str; +} + +/* ----- Utility function to add a language to a GtkListStore ----- */ +static void +add_language(GtkListStore* list_store, Language* lang) +{ + gchar* p_str = NULL; + GtkTreeIter tree_iter; + + if(lang->head_extensions == NULL || lang->impl_extensions == NULL) + return; + + /* Header extensions */ + p_str = concatenate_extensions(lang->head_extensions); + gtk_list_store_set(list_store, &tree_iter, COLUMN_HEAD, p_str, -1); + g_free(p_str); + + /* Implementation extensions */ + p_str = concatenate_extensions(lang->impl_extensions); + gtk_list_store_append(list_store, &tree_iter); + gtk_list_store_set(list_store, &tree_iter, COLUMN_IMPL, p_str, -1); + g_free(p_str); +} + +/* ----- Finally, the configuration widget ----- */ +GtkWidget* +switch_head_impl_config_widget() +{ + GtkWidget *frame, *vbox, *tree_view; + GtkWidget *hbox_buttons, *add_button, *remove_button; + GtkListStore *list_store; + GtkTreeViewColumn *column; + GtkCellRenderer *cell_renderer; + + GSList *iter_lang; + + log_func(); + + /* Frame, which is the returned widget */ + frame = gtk_frame_new(_("Switch header/implementation")); + + /* Main VBox */ + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(frame), vbox); + + /* ======= Extensions list ======= */ + + /* Add a list containing the extensions for each language (headers / implementations) */ + /* - create the GtkListStore */ + list_store = gtk_list_store_new(NB_COLUMNS, G_TYPE_STRING, G_TYPE_STRING); + + /* - fill the GtkListStore with the extensions of the languages */ + for(iter_lang = languages ; iter_lang != NULL ; iter_lang = iter_lang->next) + add_language(list_store, (Language*)(iter_lang->data)); + + /* - create the GtkTreeView */ + tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store)); + + /* - add the columns */ + /* -> headers : */ + cell_renderer = gtk_cell_renderer_text_new(); + /* TODO ! Try it... */ + /* g_object_set(G_OBJECT(cell_renderer), "editable", TRUE, NULL); */ + column = gtk_tree_view_column_new_with_attributes( _("Headers extensions"), cell_renderer, + "text", COLUMN_HEAD, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column); + + /* -> implementations : */ + cell_renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes( _("Implementations extensions"), cell_renderer, + "text", COLUMN_IMPL, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column); + + /* - finally add the GtkTreeView to the frame's vbox */ + gtk_box_pack_start(GTK_BOX(vbox), tree_view, TRUE, TRUE, 6); + + + /* ========= Buttons ======== */ + + /* HBox */ + hbox_buttons = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox_buttons, FALSE, FALSE, 0); + + /* Add the "add" button to the frame's hbox */ + add_button = gtk_button_new_from_stock(GTK_STOCK_ADD); + gtk_widget_set_sensitive(add_button, FALSE); /* TODO ! */ + g_signal_connect(G_OBJECT(add_button), "clicked", G_CALLBACK(on_configure_add_language), tree_view); + gtk_box_pack_start(GTK_BOX(hbox_buttons), add_button, FALSE, FALSE, 0); + + /* Add the "remove" button to the frame's hbox */ + remove_button = gtk_button_new_from_stock(GTK_STOCK_REMOVE); + gtk_widget_set_sensitive(remove_button, FALSE); /* TODO ! */ + g_signal_connect(G_OBJECT(remove_button), "clicked", G_CALLBACK(on_configure_remove_language), tree_view); + gtk_box_pack_start(GTK_BOX(hbox_buttons), remove_button, FALSE, FALSE, 0); + + return frame; +} + +/* --------------------------------------------------------------------- + * Callback for adding a language in the configuration dialog + * --------------------------------------------------------------------- + */ +static void +on_configure_add_language(GtkWidget* widget, gpointer data) +{ + /* TODO : test it ! */ + + GtkWidget* tree_view = (GtkWidget*)data; + GtkListStore *list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view))); + GtkTreeIter tree_iter; + GtkTreePath *path; + GtkTreeViewColumn* column = NULL; + gint nb_lines; + + /* Add a line */ + gtk_list_store_append(list_store, &tree_iter); + + /* and give the focus to it */ + nb_lines = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(list_store), NULL); + + path = gtk_tree_path_new_from_indices(nb_lines-1, -1); + + column = gtk_tree_view_get_column(GTK_TREE_VIEW(tree_view), 0); + gtk_tree_view_set_cursor(GTK_TREE_VIEW(tree_view), path, column, TRUE); + gtk_widget_grab_focus(tree_view); + + gtk_tree_path_free(path); +} + +/* --------------------------------------------------------------------- + * Callback for removing a language in the configuration dialog + * --------------------------------------------------------------------- + */ +static void +on_configure_remove_language(GtkWidget* widget, gpointer data) +{ + /* TODO ! */ +} + +/* --------------------------------------------------------------------- + * Write the configuration of the feature + * --------------------------------------------------------------------- + */ +void +write_switch_head_impl_config(GKeyFile* key_file) +{ + /* TODO ! */ + /* This is old code which needs to be updated */ + +/* lang_names = g_malloc(nb_languages * sizeof(gchar*)); + for(lang_iterator = languages_extensions, i=0 ; + lang_iterator != NULL ; + lang_iterator = lang_iterator->next, i++) + { + lang_names[i] = ((const LanguageExtensions*)(lang_iterator->data))->language_name; + } + + g_key_file_set_string_list(key_file, "switching", "languages", lang_names, nb_languages); + + g_free(lang_names); +*/ +}
Added: trunk/geany-plugins/codenav/src/switch_head_impl.h =================================================================== --- trunk/geany-plugins/codenav/src/switch_head_impl.h (rev 0) +++ trunk/geany-plugins/codenav/src/switch_head_impl.h 2009-10-18 13:17:02 UTC (rev 1016) @@ -0,0 +1,44 @@ +/* + * switch_head_impl.h - this file is part of "codenavigation", which is + * part of the "geany-plugins" project. + * + * Copyright 2009 Lionel Fuentes <funto66(at)gmail(dot)com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef SWITCH_HEAD_IMPL_H +#define SWITCH_HEAD_IMPL_H + +#include "codenavigation.h" + +/* Initialization */ +void +switch_head_impl_init(); + +/* Cleanup */ +void +switch_head_impl_cleanup(); + +/* Configuration widget */ +GtkWidget* +switch_head_impl_config_widget(); + +/* Write the configuration of the feature */ +void +write_switch_head_impl_config(GKeyFile* key_file); + +#endif /* SWITCH_HEAD_IMPL_H */
Added: trunk/geany-plugins/codenav/src/utils.c =================================================================== --- trunk/geany-plugins/codenav/src/utils.c (rev 0) +++ trunk/geany-plugins/codenav/src/utils.c 2009-10-18 13:17:02 UTC (rev 1016) @@ -0,0 +1,81 @@ +/* + * utils.c - this file is part of "codenavigation", which is + * part of the "geany-plugins" project. + * + * Copyright 2009 Lionel Fuentes <funto66(at)gmail(dot)com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "utils.h" + +/* Function which returns a newly-allocated string containing the + * extension of the file path which is given, or NULL if it did not found any extension. + */ +gchar* +get_extension(gchar* path) +{ + gchar* extension = NULL; + gchar* pc = path; + while(*pc != '\0') + { + if(*pc == '.') + extension = pc+1; + pc++; + } + + if(extension == NULL || (*extension) == '\0') + return NULL; + else + return g_strdup(extension); +} + +/* Copy a path and remove the extension + */ +gchar* +copy_and_remove_extension(gchar* path) +{ + gchar* str = NULL; + gchar* pc = NULL; + gchar* dot_pos = NULL; + + if(path == NULL || path[0] == '\0') + return NULL; + + str = g_strdup(path); + pc = str; + while(*pc != '\0') + { + if(*pc == '.') + { + dot_pos = pc; + break; + } + pc++; + } + + if(dot_pos != NULL) + *dot_pos = '\0'; + + return str; +} + +/* Comparison of strings, for use with g_slist_find_custom */ +gint +compare_strings(const gchar* a, const gchar* b) +{ + return (gint)(!utils_str_equal(a, b)); +}
Added: trunk/geany-plugins/codenav/src/utils.h =================================================================== --- trunk/geany-plugins/codenav/src/utils.h (rev 0) +++ trunk/geany-plugins/codenav/src/utils.h 2009-10-18 13:17:02 UTC (rev 1016) @@ -0,0 +1,43 @@ +/* + * utils.h - this file is part of "codenavigation", which is + * part of the "geany-plugins" project. + * + * Copyright 2009 Lionel Fuentes <funto66(at)gmail(dot)com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef UTILS_H +#define UTILS_H + +#include "codenavigation.h" + +/* Function which returns a newly-allocated string containing the + * extension of the file path which is given, or NULL if it did not found any extension. + */ +gchar* +get_extension(gchar* path); + +/* Copy a path and remove the extension + */ +gchar* +copy_and_remove_extension(gchar* path); + +/* Comparison of strings, for use with g_slist_find_custom */ +gint +compare_strings(const gchar* a, const gchar* b); + +#endif /* UTILS_H */
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.