[geany/geany-plugins] 7d56db: Merge pull request #148 from federeghe/codenav

Frank Lanitz git-noreply at xxxxx
Thu Sep 11 20:38:54 UTC 2014


Branch:      refs/heads/master
Author:      Frank Lanitz <frank at frank.uvena.de>
Committer:   Frank Lanitz <frank at frank.uvena.de>
Date:        Thu, 11 Sep 2014 20:38:54 UTC
Commit:      7d56db1c77c3c04a2cad3f79f616b83dc5554bf7
             https://github.com/geany/geany-plugins/commit/7d56db1c77c3c04a2cad3f79f616b83dc5554bf7

Log Message:
-----------
Merge pull request #148 from federeghe/codenav

codenav implementation


Modified Paths:
--------------
    codenav/AUTHORS
    codenav/ChangeLog
    codenav/README
    codenav/src/codenavigation.c
    codenav/src/codenavigation.h
    codenav/src/goto_file.c
    codenav/src/switch_head_impl.c
    codenav/src/switch_head_impl.h
    codenav/src/utils.c
    codenav/src/utils.h

Modified: codenav/AUTHORS
1 lines changed, 1 insertions(+), 0 deletions(-)
===================================================================
@@ -1 +1,2 @@
 Lionel Fuentes <funto66 at gmail.com>
+Federico Reghenzani <federico.dev at reghe.net>


Modified: codenav/ChangeLog
18 lines changed, 18 insertions(+), 0 deletions(-)
===================================================================
@@ -1,3 +1,21 @@
+2014-04-24  Federico Reghenzani <federico(dot)dev(at)reghe(dot)net>
+ * src/*:
+    Implementation of plugin preferences and minor fixes
+   
+2014-03-26  Federico Reghenzani <federico(dot)dev(at)reghe(dot)net>
+ * src/goto_file.c:
+   Implementation directory (absolute/relative path) support.
+ * src/utils.c, src/utils.h:
+   Changes strpos() into strrpos() (reverse order)
+
+2014-03-23  Federico Reghenzani <federico(dot)dev(at)reghe(dot)net>
+ * src/codenavigation.h:
+   Resolve some compiler warnings.
+ * src/goto_file.c:
+   Implementation goto_file.
+ * src/utils.c, src/utils.h:
+   Added strpos().
+
 2011-04-23  Frank Lanitz  <frlan at frank.uvena.de>
 
  * src/switch_head_impl.c:


Modified: codenav/README
23 lines changed, 18 insertions(+), 5 deletions(-)
===================================================================
@@ -6,13 +6,13 @@ Code navigation
 About
 -----
 
-This plugin adds some facilities for navigating in the code.
+This plugin adds some facilities for navigating in code files.
 
 Features
 --------
 
-* switch between header and implementation
-* go to a file by typing its name
+* Switch between header and implementation
+* Go to a file by typing its name
  
 Usage
 -----
@@ -21,6 +21,20 @@ After installed successfully, load the plugin in Geany's plugin manager
 and new menu items in the Edit menu will appear. You can
 change the keyboard shortcuts in Geany's preferences dialog.
 
+
+*Switch header/implementation*
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+This feature allows you to switch between implementation and header code 
+(e.g. between 'c' and 'h' files) using defined shortcut or by click on 
+menu item. You can edit the extensions association via preferences in 
+Geany's plugin manager. 
+
+*Go to File*
+^^^^^^^^^^^^
+You can open a file in current document directory typing its name. You
+can also enter an absolute or relative path to a file.
+
+
 Requirements
 ------------
 
@@ -28,5 +42,4 @@ Requirements
  
 Contact developers
 ------------------
-
-Lionel Fuentes <funto66 at gmail.com>
+Federico Reghenzani <federico(dot)dev(at)reghe(dot)net>


Modified: codenav/src/codenavigation.c
558 lines changed, 501 insertions(+), 57 deletions(-)
===================================================================
@@ -3,6 +3,7 @@
  *      part of the "geany-plugins" project.
  *
  *      Copyright 2009 Lionel Fuentes <funto66(at)gmail(dot)com>
+ * 		Copyright 2014 Federico Reghenzani <federico(dot)dev(at)reghe(dot)net>
  *
  *      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
@@ -20,11 +21,6 @@
  *      MA 02110-1301, USA.
  */
 
-/**
- * Code navigation plugin - plugin which adds facilities for navigating between files.
- * 2009 Lionel Fuentes.
- */
-
 #ifdef HAVE_CONFIG_H
 	#include "config.h"
 #endif
@@ -34,55 +30,150 @@
 #include "switch_head_impl.h"
 #include "goto_file.h"
 
-/************************* Global variables ***************************/
-
-/* These items are set by Geany before plugin_init() is called. */
-GeanyPlugin		*geany_plugin;
-GeanyData		*geany_data;
-GeanyFunctions	*geany_functions;
+/************************* Plugin utilities ***************************/
 
 /* Check that the running Geany supports the plugin API used below, and check
  * for binary compatibility. */
-PLUGIN_VERSION_CHECK(112)
+PLUGIN_VERSION_CHECK(200)
 
 /* All plugins must set name, description, version and author. */
 PLUGIN_SET_TRANSLATABLE_INFO(
 	LOCALEDIR,
 	GETTEXT_PACKAGE,
 	_("Code navigation"),
-	_(	"This plugin adds features to facilitate navigation between source files.\n"
-		"As for the moment, it implements :\n"
-		"- switching between a .cpp file and the corresponding .h file\n"
-		"- [opening a file by typing its name -> TODO]"), CODE_NAVIGATION_VERSION, "Lionel Fuentes")
+	_(	"This plugin adds features to facilitate navigation between source files."), 
+	CODE_NAVIGATION_VERSION, "Lionel Fuentes, Federico Reghenzani")
 
 /* 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)
 
-/***************************** Functions ******************************/
+
+/********************* Data types for the feature *********************/
+/* Column for the configuration widget */
+typedef enum
+{
+	COLUMN_IMPL = 0,
+	COLUMN_HEAD,
+	NB_COLUMNS
+} Column;
+
+/************************* Global variables ***************************/
+
+/* These items are set by Geany before plugin_init() is called. */
+GeanyPlugin		*geany_plugin;
+GeanyData		*geany_data;
+GeanyFunctions	*geany_functions;
+
+static GtkListStore *list_store;	/* for settings dialog */
+
+
+/**************************** Prototypes ******************************/
+
+GtkWidget*
+config_widget(void);
+
+static void 
+load_configuration();
+
+static void
+on_configure_add_language(GtkWidget* widget, gpointer data);
+
+static void
+on_configure_remove_language(GtkWidget* widget, gpointer data);
+
+static void
+on_configure_reset_to_default(GtkWidget* widget, gpointer data);
+
+static void
+on_configure_cell_edited(GtkCellRendererText* text, gchar* arg1, gchar* arg2, gpointer data);
 
 static void
 on_configure_response(GtkDialog *dialog, gint response, gpointer user_data);
 
-/* ---------------------------------------------------------------------
- * Called by Geany to initialize the plugin.
- * Note: data is the same as geany_data.
- * ---------------------------------------------------------------------
+/***************************** Functions ******************************/
+
+/**
+ * @brief Called by Geany to initialize the plugin.
+ * @note data is the same as geany_data.
  */
 void plugin_init(GeanyData *data)
 {
 	log_func();
 
+	/* Load configuration */
+	load_configuration();
 	/* Initialize the features */
 	switch_head_impl_init();
 	goto_file_init();
 }
 
-/* ---------------------------------------------------------------------
- * Called by Geany to show the plugin's configure dialog. This function
- * is always called after plugin_init() is called.
- * ---------------------------------------------------------------------
+/**
+ * @brief load plugin's configuration or set default values
+ * @param void 
+ * @return void
+ * 
+ */
+static void load_configuration()
+{
+	GKeyFile *config = NULL;
+	gchar *config_filename = NULL;
+	gchar **impl_list  = NULL, **head_list = NULL;
+	gsize head_list_len, impl_list_len;
+	int i;
+
+	/* Load user configuration */ 
+	config = g_key_file_new();
+	config_filename = g_strconcat(geany->app->configdir, G_DIR_SEPARATOR_S,
+		"plugins", G_DIR_SEPARATOR_S, "codenav", G_DIR_SEPARATOR_S, "codenav.conf", NULL);
+	gboolean is_configured = g_key_file_load_from_file(config, config_filename, G_KEY_FILE_NONE, NULL);
+
+	if ( is_configured ) {
+		log_debug("Loading user configuration");
+		impl_list = g_key_file_get_string_list(config, "switch_head_impl", "implementations_list", &impl_list_len, NULL);
+		head_list = g_key_file_get_string_list(config, "switch_head_impl", "headers_list", &head_list_len, NULL);
+		
+		// Wrong lists
+		if ( head_list_len != impl_list_len ) {
+			dialogs_show_msgbox(GTK_MESSAGE_WARNING,
+				_("Codenav head/impl lists should have been same length. " \
+				  "Geany will use the default configuration."));
+			fill_default_languages_list();
+		}
+		else
+			fill_languages_list((const gchar**) impl_list, (const gchar**) head_list, head_list_len);
+	}
+	else {
+		log_debug("Fresh configuration");
+		fill_default_languages_list();
+	}
+	
+	
+	/* Freeing memory */
+	g_key_file_free(config);
+	g_free(config_filename);
+
+	if ( impl_list != NULL ) {
+		for ( i = 0; i < impl_list_len; i++ )
+			g_free(impl_list[i]);
+		g_free(impl_list);
+	}
+	if ( head_list != NULL ) {
+		for ( i = 0; i < head_list_len; i++ )
+			g_free(head_list[i]);
+		g_free(head_list);
+	}
+
+}
+
+/**
+ * @brief Called by Geany to show the plugin's configure dialog. This function
+ * 		  is always called after plugin_init() is called.
+ * @param the plugin GtkWidget*
+ * @return the GtkDialog from Geany
+ * 
  */
+
 GtkWidget *plugin_configure(GtkDialog *dialog)
 {
 	GtkWidget *vbox;
@@ -92,7 +183,7 @@ GtkWidget *plugin_configure(GtkDialog *dialog)
 	vbox = gtk_vbox_new(FALSE, 6);
 
 	/* Switch header/implementation widget */
-	gtk_box_pack_start(GTK_BOX(vbox), switch_head_impl_config_widget(), TRUE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), config_widget(), TRUE, TRUE, 0);
 
 	gtk_widget_show_all(vbox);
 
@@ -102,9 +193,11 @@ GtkWidget *plugin_configure(GtkDialog *dialog)
 	return vbox;
 }
 
-/* ---------------------------------------------------------------------
- * Called by Geany before unloading the plugin.
- * ---------------------------------------------------------------------
+/**
+ * @brief Called by Geany before unloading the plugin
+ * @param void 
+ * @return void
+ * 
  */
 void plugin_cleanup(void)
 {
@@ -115,45 +208,396 @@ void plugin_cleanup(void)
 	switch_head_impl_cleanup();
 }
 
-/* ---------------------------------------------------------------------
- * Callback called when validating the configuration of the plug-in
- * ---------------------------------------------------------------------
+/**
+ * @brief 	Callback called when validating the configuration of the plug-in
+ * @param 	dialog 		the parent dialog, not very interesting here
+ * @param 	response	OK/Cancel/Apply user action
+ * @param 	user_data	NULL
+ * 
+ * @return void
+ * 
  */
 static void
 on_configure_response(GtkDialog* dialog, gint response, gpointer user_data)
 {
-	/* TODO */
-#if 0
-	GKeyFile* key_file = NULL;
-	gchar* config_dir = NULL;
-	gchar* config_filename = NULL;
+	gint i=0;
+
+	GKeyFile *config = NULL;
+	gchar *config_filename = NULL;
+	gchar *config_dir = NULL;
+	gchar *data;
+
+	gsize list_len, empty_lines;
+	gchar** head_list = NULL;
+	gchar** impl_list = NULL;
+	
+	GtkTreeIter iter;
 
-	if(response == GTK_RESPONSE_OK || response == GTK_RESPONSE_APPLY)
+	log_func();
+
+	if(response != GTK_RESPONSE_OK && response != GTK_RESPONSE_APPLY)
+		return;
+	
+	/* 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
+	 */
+
+	/* Open the GKeyFile */
+	config 	        = g_key_file_new();
+	config_filename = g_strconcat(geany->app->configdir, G_DIR_SEPARATOR_S,
+								"plugins", G_DIR_SEPARATOR_S, "codenav", 
+								G_DIR_SEPARATOR_S, "codenav.conf", NULL);
+	config_dir      = g_path_get_dirname(config_filename);
+	
+	/* Allocate the list */
+	list_len = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(list_store), NULL);
+	impl_list = g_malloc0( sizeof(gchar**) * list_len);
+	head_list = g_malloc0( sizeof(gchar**) * list_len);
+	
+	empty_lines = 0;
+	
+	if ( list_len > 0 ) {
+		// Get the first item
+		gtk_tree_model_iter_children (GTK_TREE_MODEL(list_store),&iter,NULL);
+	
+		
+		do {		/* forall elements in list... */
+						
+			gtk_tree_model_get (GTK_TREE_MODEL(list_store),&iter,
+									COLUMN_IMPL,&impl_list[i], -1);
+			gtk_tree_model_get (GTK_TREE_MODEL(list_store),&iter,
+									COLUMN_HEAD,&head_list[i], -1);
+									
+			/* If one field is empty, ignore this line (it will be replaces
+			   at next execution) */ 
+			if ( strlen(impl_list[i])==0 || strlen(head_list[i])==0 )
+				empty_lines++;
+			else
+				i++;
+		} while ( gtk_tree_model_iter_next(GTK_TREE_MODEL(list_store), &iter) );
+	}
+	
+	/* write lists */
+	g_key_file_set_string_list(config, "switch_head_impl", "implementations_list", 
+								(const gchar * const*)impl_list, list_len - empty_lines);
+	g_key_file_set_string_list(config, "switch_head_impl", "headers_list", 
+								(const gchar * const*)head_list, list_len - empty_lines);
+	
+	/* Try to create directory if not exists */
+	if (! g_file_test(config_dir, G_FILE_TEST_IS_DIR) && utils_mkdir(config_dir, TRUE) != 0)
 	{
-		/* 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
-		 */
+		dialogs_show_msgbox(GTK_MESSAGE_ERROR,
+			_("Plugin configuration directory could not be created."));
+	}
+	else
+	{
+		/* write config to file */
+		data = g_key_file_to_data(config, NULL, NULL);
+		utils_write_file(config_filename, data);
+		g_free(data);
+	}
 
-		/* Open the GKeyFile */
-		key_file = g_key_file_new();
+	/* Replace the current (runtime) languages list */
+	fill_languages_list((const gchar**)impl_list, (const gchar**)head_list, list_len - empty_lines);
+	
+	/* Freeing memory */
+	for ( i=0; i < list_len; i++ ) {
+		g_free(impl_list[i]);
+		g_free(head_list[i]);
+	}
+	g_free(impl_list);
+	g_free(head_list);
+	
+	g_free(config_dir);
+	g_free(config_filename);
+	g_key_file_free(config);
 
-		config_dir = g_strconcat(geany->app->configdir,
-			G_DIR_SEPARATOR_S "plugins" G_DIR_SEPARATOR_S "codenav" G_DIR_SEPARATOR_S, NULL);
+}
 
-		config_filename = g_strconcat(config_dir, "codenav.conf", NULL);
+ /**
+ * @brief 	Utility function to concatenate the extensions of a language,
+ * 			separated with a comma, like PHP-implode function.
+ * @param 	extensions	a list of (string) extensions
+ * 
+ * @return	concatenated string.
+ * 
+ */
+static gchar*
+concatenate_extensions(GSList* extensions)
+{
+	GSList* iter_ext;
+	gchar* p_str = NULL;
+	gchar* temp = NULL;
 
-		/* Load configuration */
-		g_key_file_load_from_file(key_file, config_filename, G_KEY_FILE_NONE, 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);
+	}
 
-		/* Write configuration */
-		write_switch_head_impl_config(key_file);
+	return p_str;
+}
 
-		/* Cleanup */
-		g_free(config_filename);
-		g_free(config_dir);
-		g_key_file_free(key_file);
+/**
+ * @brief 	Utility function to add a language to a GtkListStore
+ * @param	list	the list where to add lang
+ * @param	lang	the item to add
+ * 
+ * @return	void
+ * 
+ */
+static void
+add_language(GtkListStore* list, Language* lang)
+{
+	gchar* p_str = NULL;
+	GtkTreeIter tree_iter;
+
+	if(lang->head_extensions == NULL || lang->impl_extensions == NULL)
+		return;
+
+	/* Append an empty row */
+	gtk_list_store_append(list, &tree_iter);
+
+	/* Header extensions */
+	p_str = concatenate_extensions(lang->head_extensions);
+	gtk_list_store_set(list, &tree_iter, COLUMN_HEAD, p_str, -1);
+	g_free(p_str);
+
+	/* Implementation extensions */
+	p_str = concatenate_extensions(lang->impl_extensions);
+	gtk_list_store_set(list, &tree_iter, COLUMN_IMPL, p_str, -1);
+	g_free(p_str);
+}
+
+/**
+ * @brief 	The configuration widget
+ * 
+ * @return	The configuration widget
+ * 
+ */
+GtkWidget*
+config_widget(void)
+{
+	GtkWidget *help_label;
+	GtkWidget *frame, *vbox, *tree_view;
+	GtkWidget *hbox_buttons, *add_button, *remove_button, *reset_button;
+	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);
+
+	/* Help label */
+	help_label = gtk_label_new(_("You can specify multiple extensions by " \
+								 "separating them by commas."));
+	gtk_box_pack_start(GTK_BOX(vbox), help_label, FALSE, FALSE, 6);
+
+	/* ======= 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 = switch_head_impl_get_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 */
+	/* -> implementations : */
+	cell_renderer = gtk_cell_renderer_text_new();
+	g_object_set(G_OBJECT(cell_renderer), "editable", TRUE, NULL);
+	g_signal_connect_after(G_OBJECT(cell_renderer), "edited", G_CALLBACK(on_configure_cell_edited), GINT_TO_POINTER(COLUMN_IMPL));
+	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);
+
+	/* -> headers : */
+	cell_renderer = gtk_cell_renderer_text_new();
+	g_object_set(G_OBJECT(cell_renderer), "editable", TRUE, NULL);
+	g_signal_connect_after(G_OBJECT(cell_renderer), "edited", G_CALLBACK(on_configure_cell_edited), GINT_TO_POINTER(COLUMN_HEAD));
+	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);
+
+
+	/* - 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);
+	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);
+	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);
+
+	/* Add the "reset to default" button to the frame's hbox */
+	reset_button = gtk_button_new_with_label(_("Reset to Default"));
+	g_signal_connect(G_OBJECT(reset_button), "clicked", G_CALLBACK(on_configure_reset_to_default), NULL);
+	gtk_box_pack_start(GTK_BOX(hbox_buttons), reset_button, FALSE, FALSE, 0);
+	gtk_widget_grab_focus(tree_view);
+
+	return frame;
+}
+
+ /**
+ * @brief 	Callback for adding a language in the configuration dialog
+ * @param 	button	the button, not used here
+ * @param	data	gtktreeview where to act
+ * 
+ * @return	void
+ * 
+ */
+static void
+on_configure_add_language(GtkWidget* button, gpointer data)
+{
+	GtkWidget* tree_view = (GtkWidget*)data;
+	GtkTreeIter tree_iter;
+	GtkTreePath *path;
+	GtkTreeViewColumn* column = NULL;
+	gint nb_lines;
+
+	log_func();
+
+	/* 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_tree_path_free(path);
+}
+
+/**
+ * @brief 	Callback for removing a language in the configuration dialog
+ * @param 	button	the button, not used here
+ * @param	data	gtktreeview where to act
+ * 
+ * @return	void
+ * 
+ */
+static void
+on_configure_remove_language(GtkWidget* button, gpointer data)
+{
+	GtkTreeView* tree_view = (GtkTreeView*)data;
+	GtkTreeSelection *selection;
+	GtkTreeIter tree_iter;
+
+	log_func();
+	
+	selection = gtk_tree_view_get_selection (tree_view);
+
+	if ( ! gtk_tree_selection_get_selected(selection, NULL, &tree_iter) ) {
+		log_debug("Delete without selection!");
+		return;
 	}
-#endif
+	/* Remove the element */
+	gtk_list_store_remove(list_store, &tree_iter);
+}
+
+/**
+ * @brief 	Callback for reset to default languages in the configuration dialog
+ * @param 	button	the button, not used here
+ * @param	data	null
+ * 
+ * @return	void
+ * 
+ */
+static void
+on_configure_reset_to_default(GtkWidget* button, gpointer data)
+{
+	GSList *iter_lang;
+	GtkWidget* dialog_new;
+
+	/* ask to user if he's sure */
+	dialog_new = gtk_message_dialog_new(GTK_WINDOW(geany_data->main_widgets->window),
+											GTK_DIALOG_MODAL,
+											GTK_MESSAGE_WARNING,
+											GTK_BUTTONS_OK_CANCEL,
+											_("Are you sure you want to delete all languages " \
+											"and restore defaults?\nThis action cannot be undone."));
+	gtk_window_set_title(GTK_WINDOW(dialog_new), "Geany");
+	
+	if(gtk_dialog_run(GTK_DIALOG(dialog_new)) == GTK_RESPONSE_OK)
+	{
+		/* OK, reset! */
+		fill_default_languages_list();	
+		
+		/* clear and refill the GtkListStore with default extensions */
+		gtk_list_store_clear(list_store);
+		
+		for(iter_lang = switch_head_impl_get_languages(); 
+				iter_lang != NULL ; iter_lang = iter_lang->next)
+			add_language(list_store, (Language*)(iter_lang->data));
+	}
+	gtk_widget_destroy(dialog_new);
+
+}
+
+
+/**
+ * @brief 	Callback called when a cell has been edited in the configuration 
+ * 			dialog
+ * @param 	renderer	field object
+ * @param	path		
+ * @param	text		the new text
+ * @param	data		column where event is called
+ * 
+ * @return	void
+ * 
+ */
+static void
+on_configure_cell_edited(GtkCellRendererText* renderer, gchar* path, gchar* text, gpointer data)
+{
+	GtkTreeIter iter;
+	gchar character;
+	gint i;
+	Column col = (Column)(GPOINTER_TO_INT(data));
+	
+	log_func();
+
+	character=text[0];
+	i=1;
+	while (character != '\0') {
+		if ( ! g_ascii_isalpha(character) && character != ',' ) {
+			log_debug("Not-valid char");
+			return;	// invalid extension
+		}
+		character=text[i++];
+	}
+
+	/* Replace old text with new */
+	gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(list_store), &iter, path);
+	gtk_list_store_set(list_store, &iter, col, text, -1);
+
 }


Modified: codenav/src/codenavigation.h
40 lines changed, 21 insertions(+), 19 deletions(-)
===================================================================
@@ -1,23 +1,22 @@
 /*
- *      codenavigation.h - this file is part of "codenavigation", which is
- *      part of the "geany-plugins" project.
+ *  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>
+ *  Copyright 2009 Lionel Fuentes <funto66(at)gmail(dot)com>
+ *  Copyright 2014 Federico Reghenzani <federico(dot)dev(at)reghe(dot)net>
  *
- *      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 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.
+ *  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.
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef CODENAVIGATION_H
@@ -36,6 +35,7 @@
 #include "keybindings.h"
 #include "filetypes.h"
 #include <gdk/gdkkeysyms.h>
+
 #include <string.h>
 
 #include "switch_head_impl.h"
@@ -45,13 +45,15 @@
 #include "geanyfunctions.h"	/* this wraps geany_functions function pointers */
 
 /* Debug flag */
-/*#define CODE_NAVIGATION_DEBUG
-*/
+/*#define CODE_NAVIGATION_DEBUG*/
 
-#define CODE_NAVIGATION_VERSION "0.1"
+#define CODE_NAVIGATION_VERSION "0.2"
 
 /* Log utilities */
 #ifdef CODE_NAVIGATION_DEBUG
+#include <glib/gprintf.h>
+
+
 static void log_debug(const gchar* s, ...)
 {
 	gchar* format = g_strconcat("[CODENAV DEBUG] : ", s, "\n", NULL);
@@ -64,7 +66,7 @@ static void log_debug(const gchar* s, ...)
 
 #define log_func() g_print("[CODENAV FUNC] : %s", G_STRFUNC)
 #else
-static void log_debug(const gchar* s, ...) {}
+#define log_debug(...) {}
 #define log_func() {}
 #endif
 


Modified: codenav/src/goto_file.c
299 lines changed, 253 insertions(+), 46 deletions(-)
===================================================================
@@ -1,23 +1,22 @@
 /*
- *      goto_file.c - this file is part of "codenavigation", which is
- *      part of the "geany-plugins" project.
+ *  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>
+ *  Copyright 2009 Lionel Fuentes <funto66(at)gmail(dot)com>
+ *  Copyright 2014 Federico Reghenzani <federico(dot)dev(at)reghe(dot)net>
+ * 
+ *  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 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.
  *
- *      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.
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -26,23 +25,35 @@
 #include <geanyplugin.h>
 
 #include "goto_file.h"
+#include "utils.h"
+
+#define MAX_FILENAME_LENGTH 255
 
 /******************* Global variables for the feature *****************/
 
 static GtkWidget* menu_item = NULL;
+gchar *directory_ref = NULL;
 
-/********************** Functions for the feature *********************/
+/********************** Prototypes *********************/
+static void
+menu_item_activate(guint);
+
+static GtkTreeModel* 
+build_file_list(const gchar*, const gchar*);
 
-/* ---------------------------------------------------------------------
- * Callback when the menu item is clicked.
- * ---------------------------------------------------------------------
- */
 static void
-menu_item_activate(guint key_id);
+directory_check(GtkEntry*, GtkEntryCompletion*);
+
+static GtkWidget*
+create_dialog(GtkWidget**, GtkTreeModel*);
 
-/* ---------------------------------------------------------------------
- * Initialization
- * ---------------------------------------------------------------------
+/********************** Functions for the feature *********************/
+
+/**
+ * @brief 	Initialization function called in plugin_init
+ * @param 	void
+ * @return	void
+ * 
  */
 void
 goto_file_init(void)
@@ -54,7 +65,7 @@ goto_file_init(void)
 	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"));
+	menu_item = gtk_menu_item_new_with_mnemonic(_("Go to File..."));
 	gtk_widget_show(menu_item);
 	gtk_container_add(GTK_CONTAINER(edit_menu), menu_item);
 	ui_add_document_sensitive(menu_item);
@@ -68,46 +79,242 @@ goto_file_init(void)
  							(GeanyKeyCallback)(&menu_item_activate),
  							GDK_g, GDK_MOD1_MASK | GDK_SHIFT_MASK,
  							"goto_file",
- 							_("Goto file"),	/* used in the Preferences dialog */
+ 							_("Go to File"),	/* used in the Preferences dialog */
  							menu_item);
 }
 
-/* ---------------------------------------------------------------------
- * Cleanup
- * ---------------------------------------------------------------------
+/**
+ * @brief 	Cleanup function called in plugin_cleanup
+ * @param 	void
+ * @return	void
+ * 
  */
 void
 goto_file_cleanup(void)
 {
 	log_func();
-
 	gtk_widget_destroy(menu_item);
 }
 
-/* ---------------------------------------------------------------------
- * Callback when the menu item is clicked.
- * ---------------------------------------------------------------------
+/**
+ * @brief 	Populate the file list with file list of directory 
+ * @param 	const char* dirname	the directory where to find files
+ * @param	const char* prefix	file prefix (the path)
+ * @return	GtkTreeModel*
+ * 
+ */
+static GtkTreeModel* 
+build_file_list(const gchar* dirname, const gchar* prefix)
+{
+	GtkListStore *ret_list;
+	GtkTreeIter iter;
+	ret_list = gtk_list_store_new (1, G_TYPE_STRING);
+	
+	GSList* file_iterator;
+	GSList* files_list;	/* used to free later the sub-elements*/
+	gchar *file;
+	gchar *pathfile;
+	guint files_n;
+
+	files_list = file_iterator = utils_get_file_list(dirname, &files_n, NULL);
+	
+	for( ; file_iterator; file_iterator = file_iterator->next) 
+	{
+		file = file_iterator->data;		
+		
+		pathfile = g_build_filename(dirname,file,NULL);   
+	
+        /* Append the element to model list */
+        gtk_list_store_append (ret_list, &iter);
+        gtk_list_store_set (ret_list, &iter, 0, 
+                            g_strconcat(prefix, file, NULL), -1);
+		g_free(pathfile);
+	}
+	
+	g_slist_foreach(files_list, (GFunc) g_free, NULL);
+	g_slist_free(files_list);
+	
+	return GTK_TREE_MODEL(ret_list);
+ 
+}
+
+/**
+ * @brief 	Entry callback function for sub-directory search 
+ * @param 	GtkEntry* entry			entry object
+ * @param	GtkEntryCompletion* completion	completion object
+ * @return	void
+ * 
+ */
+static void
+directory_check(GtkEntry* entry, GtkEntryCompletion* completion)
+{
+    static GtkTreeModel *old_model = NULL;
+   	GtkTreeModel* completion_list;
+    static gchar *curr_dir = NULL;
+    gchar *new_dir, *new_dir_path; 
+    const gchar *text;
+    
+    text = gtk_entry_get_text(entry);
+    gint dir_sep = strrpos(text, G_DIR_SEPARATOR_S);
+    
+    /* No subdir separator found */
+    if (dir_sep == -1)
+    {
+        if (old_model != NULL)
+        {   /* Restore the no-sub-directory model */
+            log_debug("Restoring old model!");
+            gtk_entry_completion_set_model (completion, old_model);
+            old_model = NULL;
+            g_free(curr_dir);
+            curr_dir = NULL;
+        }
+        return;
+    }
+    
+    new_dir = g_strndup (text, dir_sep+1);
+    /* I've already inserted new model completion for sub-dir elements? */
+    if ( g_strcmp0 (new_dir, curr_dir) == 0 )
+        return;
+
+    if ( curr_dir != NULL )
+        g_free(curr_dir);
+
+    curr_dir = new_dir;
+
+    /* Save the completion_mode for future restore. */
+    if (old_model == NULL)
+        old_model = gtk_entry_completion_get_model(completion);
+
+    log_debug("New completion list!");
+
+    if ( g_path_is_absolute(new_dir) )
+        new_dir_path = new_dir;
+    else
+        new_dir_path = g_build_filename(directory_ref, new_dir, NULL);
+
+    /* Build the new file list for completion */
+    completion_list = build_file_list(new_dir_path, new_dir);
+  	gtk_entry_completion_set_model (completion, completion_list);
+    g_object_unref(completion_list);
+}
+
+
+/**
+ * @brief 	Create the dialog, return the entry object to get the
+ * 		response from user 
+ * @param 	GtkWidget **dialog			entry object
+ * @param	GtkTreeModel *completion_model	completion object
+ * @return	GtkWidget* entry
+ * 
+ */
+static GtkWidget*
+create_dialog(GtkWidget **dialog, GtkTreeModel *completion_model)
+{
+	GtkWidget *entry;
+	GtkWidget *label;
+	GtkWidget *vbox;
+	GtkEntryCompletion *completion;
+		
+	*dialog = gtk_dialog_new_with_buttons(_("Go to File..."), GTK_WINDOW(geany->main_widgets->window),
+	GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+	GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
+	
+	gtk_dialog_set_default_response(GTK_DIALOG(*dialog), GTK_RESPONSE_ACCEPT);
+	
+	gtk_widget_set_name(*dialog, "GotoFile");
+	vbox = ui_dialog_vbox_new(GTK_DIALOG(*dialog));
+
+	label = gtk_label_new(_("Enter the file you want to open:"));
+	gtk_container_add(GTK_CONTAINER(vbox), label);
+
+	/* Entry definition */
+	entry = gtk_entry_new();
+	gtk_container_add(GTK_CONTAINER(vbox), entry);
+	gtk_entry_set_text(GTK_ENTRY(entry), "");
+	gtk_entry_set_max_length(GTK_ENTRY(entry), MAX_FILENAME_LENGTH);
+	gtk_entry_set_width_chars(GTK_ENTRY(entry), 40);
+	gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);   /* 'enter' key */
+    
+	/* Completion definition */
+	completion = gtk_entry_completion_new();
+	gtk_entry_set_completion(GTK_ENTRY(entry), completion);
+	gtk_entry_completion_set_model (completion, completion_model);
+	
+	/* Completion options */
+	gtk_entry_completion_set_inline_completion(completion, 1);
+	gtk_entry_completion_set_text_column (completion, 0);
+
+	/* Signals */
+	g_signal_connect_after(GTK_ENTRY(entry), "changed", 
+                               G_CALLBACK(directory_check), completion);
+
+	gtk_widget_show_all(*dialog);
+
+	return entry;
+}
+
+/**
+ * @brief 	Callback when the menu item is clicked.
+ * @param 	guint key_id	not used
+ * @return	void
+ * 
  */
 static void
 menu_item_activate(guint key_id)
 {
-	GtkWidget *dialog;
+	GtkWidget* dialog;
+	GtkWidget* dialog_new = NULL;
+	GtkWidget* dialog_entry;
+	GtkTreeModel* completion_list;
+	GeanyDocument* current_doc = document_get_current();
+	gchar *chosen_path;
+	const gchar *chosen_file;
+	gint response;
 
 	log_func();
 
-	/* TODO */
-	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");
+	if(current_doc == NULL || current_doc->file_name == NULL || current_doc->file_name[0] == '\0')
+		return;
+		
+	/* Build current directory listing */
+	directory_ref = g_path_get_dirname(current_doc->file_name);
+	completion_list = build_file_list(directory_ref, "");
+
+	/* Create the user dialog and get response */
+	dialog_entry = create_dialog(&dialog, completion_list);
+	response = gtk_dialog_run(GTK_DIALOG(dialog));
+
+	/* Filename */
+	chosen_file = gtk_entry_get_text(GTK_ENTRY(dialog_entry));
+	/* Path + Filename */
+	chosen_path = g_build_filename(directory_ref, chosen_file, NULL);
 
-	gtk_window_set_title(GTK_WINDOW(dialog), "Goto file...");
+	if ( response == GTK_RESPONSE_ACCEPT )
+	{
+		log_debug("Trying to open: %s", chosen_path);
+		if ( ! g_file_test(chosen_path, G_FILE_TEST_EXISTS) )
+		{
+			log_debug("File not found.");
 
-	gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
-		_("(From the %s plugin)"), geany_plugin->info->name);
+			dialog_new = 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?"), chosen_file);
+			gtk_window_set_title(GTK_WINDOW(dialog_new), "Geany");
+			if(gtk_dialog_run(GTK_DIALOG(dialog_new)) == GTK_RESPONSE_OK)
+			{
+				document_new_file(chosen_path, current_doc->file_type, NULL);
+				document_set_text_changed(document_get_current(), TRUE);
+			}
+			gtk_widget_destroy(dialog_new);
+		}
+		else
+			document_open_file(chosen_path, FALSE, NULL, NULL);
+	}
 
-	gtk_dialog_run(GTK_DIALOG(dialog));
+	/* Freeing memory */
 	gtk_widget_destroy(dialog);
+	g_free(directory_ref);
+	g_object_unref (completion_list);
 }


Modified: codenav/src/switch_head_impl.c
353 lines changed, 100 insertions(+), 253 deletions(-)
===================================================================
@@ -3,6 +3,7 @@
  *      part of the "geany-plugins" project.
  *
  *      Copyright 2009 Lionel Fuentes <funto66(at)gmail(dot)com>
+ * 		Copyright 2014 Federico Reghenzani <federico(dot)dev(at)reghe(dot)net>
  *
  *      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
@@ -28,55 +29,39 @@
 #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;
+/****************************** Useful macro **************************/
+#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)); }
 
-/* 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(void);
+/**************************** Prototypes ******************************/
+void 
+languages_clean(void);
 
 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);
-
-static void
-on_configure_cell_edited(GtkCellRendererText* text, gchar* arg1, gchar* arg2, gpointer data);
+/********************** Functions for the feature *********************/
 
-/* ---------------------------------------------------------------------
- *  Initialization
- * ---------------------------------------------------------------------
+/**
+ * @brief Initialization
+ * @param void 
+ * @return void
+ * 
  */
 void
 switch_head_impl_init(void)
 {
 	GtkWidget* edit_menu;
-
 	log_func();
 
 	edit_menu = ui_lookup_widget(geany->main_widgets->window, "edit1_menu");
@@ -99,53 +84,107 @@ switch_head_impl_init(void)
  							_("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
- * ---------------------------------------------------------------------
+
+/**
+ * @brief Default plugin cleanup
+ * @param void 
+ * @return void
+ * 
  */
 void
 switch_head_impl_cleanup(void)
 {
-	GSList* iter = NULL;
-
 	log_func();
 
 	gtk_widget_destroy(menu_item);
+	languages_clean();
+}
+
+/**
+ * @brief	Free and cleanup all item in languages array, and set languages
+ * 			to null
+ * @param void 
+ * @return void
+ * 
+ */
+void languages_clean(void)
+{
+	GSList* iter = NULL;
 
 	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->head_extensions, (GFunc)(&g_free), NULL);
+		g_slist_free(lang->head_extensions);
 
 		g_slist_foreach(lang->impl_extensions, (GFunc)(&g_free), NULL);
 		g_slist_free(lang->impl_extensions);
 	}
 
 	g_slist_free(languages);
+
+	languages = NULL;
 }
 
+/**
+ * @brief	Fill the languages variable with passed arguments.
+ * @param	impl_list	list of implementation extensions 
+ * @param	head_list	list of header extensions
+ * @return	void
+ * 
+ */
+void
+fill_languages_list(const gchar** impl_list, const gchar** head_list, gsize n)
+{
+	gchar **splitted_list;
+	Language* lang = NULL;
+	gint i, j;
+	
+	languages_clean();
+
+	for ( i=0; i<n; i++ ) {
+		lang = g_malloc0(sizeof(Language));
+		
+		/* check if current item has no head or impl */
+		if ( strlen(impl_list[i])==0 || strlen(head_list[i])==0 )
+			continue;
+		
+		/* Set language implementation extensions */
+		splitted_list = g_strsplit(impl_list[i], ",", 0);
+		for ( j=0; splitted_list[j] != NULL; j++ )
+			IMPL_PREPEND(splitted_list[j]);
+		g_strfreev(splitted_list);
+		
+		/* Set language header extensions */
+		splitted_list = g_strsplit(head_list[i], ",", 0);
+		for ( j=0; splitted_list[j] != NULL; j++ )
+			HEAD_PREPEND(splitted_list[j]);
+		g_strfreev(splitted_list);
+		
+		/* add current language to main list */
+		languages = g_slist_prepend(languages, lang);
+	}
+	
+	/* reverse the list to match correct order */
+	languages = g_slist_reverse(languages);
+
+}
 
-/* ---------------------------------------------------------------------
- *  Initialize the "languages" list to the default known languages
- * ---------------------------------------------------------------------
+/**
+ * @brief	Initialize the "languages" list to the default known languages
+ * @param	void
+ * @return	void
+ * 
  */
-static void
+void
 fill_default_languages_list(void)
 {
 	Language* lang = NULL;
 
-	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)); }
+	languages_clean();
 
 	/* C/C++ */
 	lang = g_malloc0(sizeof(Language));
@@ -195,13 +234,13 @@ fill_default_languages_list(void)
 	/* Done : */
 	languages = g_slist_reverse(languages);
 
-#undef HEAD_PREPEND
-#undef IMPL_PREPEND
 }
 
-/* ---------------------------------------------------------------------
- *  Callback when the menu item is clicked.
- * ---------------------------------------------------------------------
+/**
+ * @brief	Callback when the menu item is clicked.
+ * @param	key_id	not used
+ * @return	void
+ * 
  */
 static void
 menu_item_activate(guint key_id)
@@ -395,205 +434,13 @@ menu_item_activate(guint key_id)
 	}
 }
 
-/* ---------------------------------------------------------------------
- *  Configuration widget
- * ---------------------------------------------------------------------
+/**
+ * @brief	Extern function to get languages.
+ * @param	void
+ * @return	GSList*	languages list
+ * 
  */
-
-/* ----- Utility function to concatenate the extensions of a -----
- *       language, separated with a comma. */
-static gchar*
-concatenate_extensions(GSList* extensions)
+GSList* switch_head_impl_get_languages()
 {
-	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;
-
-	/* Append an empty row */
-	gtk_list_store_append(list_store, &tree_iter);
-
-	/* 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_set(list_store, &tree_iter, COLUMN_IMPL, p_str, -1);
-	g_free(p_str);
-}
-
-/* ----- Finally, the configuration widget ----- */
-GtkWidget*
-switch_head_impl_config_widget(void)
-{
-	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();
-	g_object_set(G_OBJECT(cell_renderer), "editable", TRUE, NULL);
-	g_signal_connect(G_OBJECT(cell_renderer), "edited", G_CALLBACK(on_configure_cell_edited), GINT_TO_POINTER(COLUMN_HEAD));
-	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();
-	g_object_set(G_OBJECT(cell_renderer), "editable", TRUE, NULL);
-	g_signal_connect(G_OBJECT(cell_renderer), "edited", G_CALLBACK(on_configure_cell_edited), GINT_TO_POINTER(COLUMN_IMPL));
-	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);
-	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)
-{
-	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);
-
-	/* TODO : why isn't the cell being edited, although we say "TRUE" as last parameter ?? */
-	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 ! */
-}
-
-/* ---------------------------------------------------------------------
- * Callback called when a cell has been edited in the configuration dialog
- * ---------------------------------------------------------------------
- */
-static void
-on_configure_cell_edited(GtkCellRendererText* text, gchar* arg1, gchar* arg2, gpointer data)
-{
-	/* TODO !! */
-	/* Column col = (Column)(GPOINTER_TO_INT(data)); */
-	log_debug("arg1 == %s, arg2 == %s\n", arg1, arg2);
-}
-
-/* ---------------------------------------------------------------------
- * 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);
-*/
+	return languages;
 }


Modified: codenav/src/switch_head_impl.h
23 lines changed, 18 insertions(+), 5 deletions(-)
===================================================================
@@ -3,6 +3,7 @@
  *      part of the "geany-plugins" project.
  *
  *      Copyright 2009 Lionel Fuentes <funto66(at)gmail(dot)com>
+ * 		Copyright 2014 Federico Reghenzani <federico(dot)dev(at)reghe(dot)net>
  *
  *      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
@@ -25,6 +26,14 @@
 
 #include "codenavigation.h"
 
+/* Structure representing a handled language */
+typedef struct
+{
+	const gchar* name;			/* currently not used */
+	GSList* head_extensions;	/* e.g. : "h", "hpp", ... */
+	GSList* impl_extensions; /* e.g. : "cpp", "cxx", ... */
+} Language;
+
 /* Initialization */
 void
 switch_head_impl_init(void);
@@ -33,12 +42,16 @@ switch_head_impl_init(void);
 void
 switch_head_impl_cleanup(void);
 
-/* Configuration widget */
-GtkWidget*
-switch_head_impl_config_widget(void);
+/* Languages-related */
+void
+fill_default_languages_list(void);
 
-/* Write the configuration of the feature */
 void
-write_switch_head_impl_config(GKeyFile* key_file);
+fill_languages_list(const gchar**, const gchar**, gsize);
+
+
+
+GSList* switch_head_impl_get_languages();
+
 
 #endif /* SWITCH_HEAD_IMPL_H */


Modified: codenav/src/utils.c
67 lines changed, 48 insertions(+), 19 deletions(-)
===================================================================
@@ -1,29 +1,32 @@
 /*
- *      utils.c - this file is part of "codenavigation", which is
- *      part of the "geany-plugins" project.
+ *  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>
+ *  Copyright 2009 Lionel Fuentes <funto66(at)gmail(dot)com>
+ *  Copyright 2014 Federico Reghenzani <federico(dot)dev(at)reghe(dot)net>
  *
- *      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 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.
+ *  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.
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #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.
+ /**
+ * @brief	Function which returns the extension of the file path which 
+ * 			is given, or NULL if it did not found any extension.
+ * @param 	gchar*	the file path 
+ * @return	gchar*	newly-allocated string containing the extension
+ * 
  */
 gchar*
 get_extension(gchar* path)
@@ -43,7 +46,11 @@ get_extension(gchar* path)
 		return g_strdup(extension);
 }
 
-/* Copy a path and remove the extension
+/**
+ * @brief	Copy a path and remove the extension 
+ * @param 	gchar*	the file path 
+ * @return	gchar*	newly-allocated string containing the filename without ext
+ * 
  */
 gchar*
 copy_and_remove_extension(gchar* path)
@@ -73,9 +80,31 @@ copy_and_remove_extension(gchar* path)
 	return str;
 }
 
-/* Comparison of strings, for use with g_slist_find_custom */
+/**
+ * @brief	Comparison of strings, for use with g_slist_find_custom 
+ * @param 	const gchar*, const gchar* 
+ * @return	gint
+ * 
+ */
 gint
 compare_strings(const gchar* a, const gchar* b)
 {
 	return (gint)(!utils_str_equal(a, b));
 }
+
+/**
+ * @brief	A PHP-like reverse strpos implementation 
+ * @param 	const gchar*	haystack
+ * @param   const gchar*	needle 
+ * @return	gint	position or -1 if not found
+ * 
+ */
+gint
+strrpos(const gchar *haystack, const gchar *needle)
+{
+   char *p = g_strrstr_len(haystack, -1, needle);
+   if (p)
+	  return p - haystack;
+   return -1;   // not found
+}
+


Modified: codenav/src/utils.h
4 lines changed, 4 insertions(+), 0 deletions(-)
===================================================================
@@ -3,6 +3,7 @@
  *      part of the "geany-plugins" project.
  *
  *      Copyright 2009 Lionel Fuentes <funto66(at)gmail(dot)com>
+ *      Copyright 2014 Federico Reghenzani <federico(dot)dev(at)reghe(dot)net>
  *
  *      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
@@ -40,4 +41,7 @@ copy_and_remove_extension(gchar* path);
 gint
 compare_strings(const gchar* a, const gchar* b);
 
+gint
+strrpos(const gchar *haystack, const gchar *needle);
+
 #endif /* UTILS_H */



--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Plugins-Commits mailing list