SF.net SVN: geany-plugins:[1016] trunk/geany-plugins/codenav/src

funto66 at users.sourceforge.net funto66 at xxxxx
Sun Oct 18 13:17:03 UTC 2009


Revision: 1016
          http://geany-plugins.svn.sourceforge.net/geany-plugins/?rev=1016&view=rev
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.



More information about the Plugins-Commits mailing list