[geany/geany-plugins] 8ec8bb: Merge pull request #783 from techee/projorg_file_ops

elextr git-noreply at xxxxx
Mon Apr 1 01:03:26 UTC 2019


Branch:      refs/heads/master
Author:      elextr <elextr at gmail.com>
Committer:   GitHub <noreply at github.com>
Date:        Mon, 01 Apr 2019 01:03:26 UTC
Commit:      8ec8bb339a6e130c858401d9de4bf265a1a28b3e
             https://github.com/geany/geany-plugins/commit/8ec8bb339a6e130c858401d9de4bf265a1a28b3e

Log Message:
-----------
Merge pull request #783 from techee/projorg_file_ops

 Add file operations to Project Organizer v2


Modified Paths:
--------------
    projectorganizer/src/prjorg-project.c
    projectorganizer/src/prjorg-project.h
    projectorganizer/src/prjorg-sidebar.c
    projectorganizer/src/prjorg-utils.c
    projectorganizer/src/prjorg-utils.h

Modified: projectorganizer/src/prjorg-project.c
11 lines changed, 8 insertions(+), 3 deletions(-)
===================================================================
@@ -118,6 +118,8 @@ static GSList *get_file_list(const gchar *utf8_path, GSList *patterns,
 						ignored_file_patterns, visited_paths);
 				if (lst)
 					list = g_slist_concat(list, lst);
+				else
+					list = g_slist_prepend(list, g_build_path(G_DIR_SEPARATOR_S, utf8_filename, PROJORG_DIR_ENTRY, NULL));
 			}
 		}
 		else if (g_file_test(locale_filename, G_FILE_TEST_IS_REGULAR))
@@ -284,16 +286,19 @@ static void regenerate_tags(PrjOrgRoot *root, gpointer user_data)
 	g_hash_table_iter_init(&iter, root->file_table);
 	while (g_hash_table_iter_next(&iter, &key, &value))
 	{
-		TMSourceFile *sf;
+		TMSourceFile *sf = NULL;
 		gchar *utf8_path = key;
 		gchar *locale_path = utils_get_locale_from_utf8(utf8_path);
+		gchar *basename = g_path_get_basename(locale_path);
 
-		sf = tm_source_file_new(locale_path, filetypes_detect(utf8_path)->name);
-		if (sf && !document_find_by_filename(utf8_path))
+		if (g_strcmp0(PROJORG_DIR_ENTRY, basename) != 0)
+			sf = tm_source_file_new(locale_path, filetypes_detect(utf8_path)->name);
+		if (sf && !document_find_by_filename(utf8_path)  )
 			g_ptr_array_add(source_files, sf);
 
 		g_hash_table_insert(file_table, g_strdup(utf8_path), sf);
 		g_free(locale_path);
+		g_free(basename);
 	}
 	g_hash_table_destroy(root->file_table);
 	root->file_table = file_table;


Modified: projectorganizer/src/prjorg-project.h
5 lines changed, 5 insertions(+), 0 deletions(-)
===================================================================
@@ -63,4 +63,9 @@ void prjorg_project_remove_single_tm_file(gchar *utf8_filename);
 
 gboolean prjorg_project_is_in_project(const gchar *utf8_filename);
 
+/* In the code we create a list of all files but we want to keep empty directories
+ * in the list for which we create a fake file name with the PROJORG_DIR_ENTRY
+ * value. */
+#define PROJORG_DIR_ENTRY "..."
+
 #endif


Modified: projectorganizer/src/prjorg-sidebar.c
231 lines changed, 231 insertions(+), 0 deletions(-)
===================================================================
@@ -105,6 +105,11 @@ static struct
 	GtkWidget *find_tag;
 	GtkWidget *expand;
 	GtkWidget *remove_external_dir;
+
+	GtkWidget *create_file;
+	GtkWidget *create_dir;
+	GtkWidget *rename;
+	GtkWidget *delete;
 } s_popup_menu;
 
 
@@ -350,6 +355,169 @@ static void on_remove_external_dir(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_U
 }
 
 
+// returned string must be freed
+static gchar* parent_dir_for_create()
+{
+	GtkTreeSelection *treesel;
+	GtkTreeModel *model;
+	GtkTreeIter iter, parent;
+	gchar *path = NULL;
+
+	treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(s_file_view));
+	if (gtk_tree_selection_get_selected(treesel, &model, &iter))
+	{
+		path = build_path(&iter);
+		if (!g_file_test(path, G_FILE_TEST_IS_DIR))
+		{
+			g_free(path);
+			path = NULL;
+			if (gtk_tree_model_iter_parent(model, &parent, &iter))
+				path = build_path(&parent);
+		}
+	}
+	return path;
+}
+
+
+static void on_create_file(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data)
+{
+	gchar *dir, *name;
+
+	dir = parent_dir_for_create();
+	if (dir == NULL)
+		return;
+
+	name = dialogs_show_input(_("New File"), GTK_WINDOW(geany->main_widgets->window),
+			_("File name:"), _("newfile.txt"));
+
+	if (name != NULL)
+	{
+		gchar *path = g_build_path(G_DIR_SEPARATOR_S, dir, name, NULL);
+
+		if (create_file(path))
+		{
+			open_file(path);
+			//TODO: don't rescan the whole project, only change the affected file
+			prjorg_project_rescan();
+			prjorg_sidebar_update(TRUE);
+		}
+		else
+			dialogs_show_msgbox(GTK_MESSAGE_ERROR, _("Cannot create file '%s'."), path);
+		g_free(path);
+	}
+	g_free(name);
+	g_free(dir);
+}
+
+
+static void on_create_dir(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data)
+{
+	gchar *dir, *name;
+
+	dir = parent_dir_for_create();
+	if (dir == NULL)
+		return;
+
+	name = dialogs_show_input(_("New Directory"), GTK_WINDOW(geany->main_widgets->window),
+			_("Directory name:"), _("newdir"));
+
+	if (name != NULL)
+	{
+		gchar *path = g_build_path(G_DIR_SEPARATOR_S, dir, name, NULL);
+
+		if (create_dir(path))
+		{
+			//TODO: don't rescan the whole project, only change the affected directory
+			prjorg_project_rescan();
+			prjorg_sidebar_update(TRUE);
+		}
+		else
+			dialogs_show_msgbox(GTK_MESSAGE_ERROR, _("Cannot create directory '%s'."), path);
+		g_free(path);
+	}
+	g_free(name);
+	g_free(dir);
+}
+
+
+static void on_rename(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data)
+{
+	GtkTreeSelection *treesel;
+	GtkTreeModel *model;
+	GtkTreeIter iter, parent;
+	gchar *name, *dir;
+
+	treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(s_file_view));
+	if (!gtk_tree_selection_get_selected(treesel, &model, &iter))
+		return;
+	if (!gtk_tree_model_iter_parent(model, &parent, &iter))
+		return;
+	dir = build_path(&parent);
+	if (dir == NULL)
+		return;
+
+	gtk_tree_model_get(model, &iter, FILEVIEW_COLUMN_NAME, &name, -1);
+	if (name != NULL)
+	{
+		gchar *newname = dialogs_show_input(_("Rename"), GTK_WINDOW(geany->main_widgets->window),
+				_("New name:"), name);
+
+		if (newname != NULL)
+		{
+			gchar *oldpath = g_build_path(G_DIR_SEPARATOR_S, dir, name, NULL);
+			gchar *newpath = g_build_path(G_DIR_SEPARATOR_S, dir, newname, NULL);
+			if (rename_file_or_dir(oldpath, newpath))
+			{
+				//TODO: don't rescan the whole project, only change the affected file
+				prjorg_project_rescan();
+				prjorg_sidebar_update(TRUE);
+			}
+			else
+				dialogs_show_msgbox(GTK_MESSAGE_ERROR, _("Cannot rename '%s' to '%s'."),
+						oldpath, newpath);
+			g_free(oldpath);
+			g_free(newpath);
+		}
+		g_free(newname);
+	}
+	g_free(dir);
+	g_free(name);
+}
+
+
+static void on_delete(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data)
+{
+	GtkTreeSelection *treesel;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gchar *name;
+
+	treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(s_file_view));
+	if (!gtk_tree_selection_get_selected(treesel, &model, &iter))
+		return;
+
+	gtk_tree_model_get(model, &iter, FILEVIEW_COLUMN_NAME, &name, -1);
+
+	if (dialogs_show_question(_("Are you sure you want to delete '%s'?"), name))
+	{
+		gchar *path = build_path(&iter);
+
+		if (remove_file_or_dir(path))
+			close_file(path);
+		else
+			dialogs_show_msgbox(GTK_MESSAGE_ERROR, _("Cannot delete file '%s'."), path);
+
+		g_free(path);
+
+		//TODO: don't rescan the whole project, only change the affected file
+		prjorg_project_rescan();
+		prjorg_sidebar_update(TRUE);
+	}
+
+	g_free(name);
+}
+
+
 static void find_file_recursive(GtkTreeIter *iter, gboolean case_sensitive, gboolean full_path, GPatternSpec *pattern)
 {
 	GtkTreeModel *model = GTK_TREE_MODEL(s_file_store);
@@ -789,6 +957,8 @@ static gboolean on_button_release(G_GNUC_UNUSED GtkWidget * widget, GdkEventButt
 		GtkTreeSelection *treesel;
 		GtkTreeModel *model;
 		GtkTreeIter iter;
+		gboolean delete_enabled = TRUE;
+		gchar *path;
 
 		treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(s_file_view));
 
@@ -798,6 +968,23 @@ static gboolean on_button_release(G_GNUC_UNUSED GtkWidget * widget, GdkEventButt
 		gtk_widget_set_sensitive(s_popup_menu.expand, gtk_tree_model_iter_has_child(model, &iter));
 		gtk_widget_set_sensitive(s_popup_menu.remove_external_dir, topmost_selected(model, &iter, FALSE));
 
+		path = build_path(&iter);
+		SETPTR(path, utils_get_locale_from_utf8(path));
+		if (g_file_test(path, G_FILE_TEST_IS_DIR))
+		{
+			GDir *dir = g_dir_open(path, 0, NULL);
+
+			delete_enabled = FALSE;
+			if (dir)
+			{
+				delete_enabled = g_dir_read_name(dir) == NULL;
+				g_dir_close(dir);
+			}
+		}
+		g_free(path);
+
+		gtk_widget_set_sensitive(s_popup_menu.delete, delete_enabled);
+
 		gtk_menu_popup(GTK_MENU(s_popup_menu.widget), NULL, NULL, NULL, NULL,
 						event->button, event->time);
 		return TRUE;
@@ -900,6 +1087,10 @@ static void create_branch(gint level, GSList *leaf_list, GtkTreeIter *parent,
 		GtkTreeIter iter;
 		gchar **path_arr = elem->data;
 		GIcon *icon = NULL;
+
+		if (g_strcmp0(PROJORG_DIR_ENTRY, path_arr[level]) == 0)
+			continue;
+
 		gchar *content_type = g_content_type_guess(path_arr[level], NULL, 0, NULL);
 
 		if (content_type)
@@ -1472,6 +1663,46 @@ void prjorg_sidebar_init(void)
 	gtk_widget_show(item);
 	gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item);
 
+	image = gtk_image_new_from_stock(GTK_STOCK_FILE, GTK_ICON_SIZE_MENU);
+	gtk_widget_show(image);
+	item = gtk_image_menu_item_new_with_mnemonic(_("New File..."));
+	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
+	gtk_widget_show(item);
+	gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item);
+	g_signal_connect((gpointer) item, "activate", G_CALLBACK(on_create_file), NULL);
+	s_popup_menu.create_file = item;
+
+	image = gtk_image_new_from_stock(GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU);
+	gtk_widget_show(image);
+	item = gtk_image_menu_item_new_with_mnemonic(_("New Directory..."));
+	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
+	gtk_widget_show(item);
+	gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item);
+	g_signal_connect((gpointer) item, "activate", G_CALLBACK(on_create_dir), NULL);
+	s_popup_menu.create_dir = item;
+
+	image = gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU);
+	gtk_widget_show(image);
+	item = gtk_image_menu_item_new_with_mnemonic(_("Rename..."));
+	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
+	gtk_widget_show(item);
+	gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item);
+	g_signal_connect((gpointer) item, "activate", G_CALLBACK(on_rename), NULL);
+	s_popup_menu.rename = item;
+
+	image = gtk_image_new_from_stock(GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU);
+	gtk_widget_show(image);
+	item = gtk_image_menu_item_new_with_mnemonic(_("Delete"));
+	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
+	gtk_widget_show(item);
+	gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item);
+	g_signal_connect((gpointer) item, "activate", G_CALLBACK(on_delete), NULL);
+	s_popup_menu.delete = item;
+
+	item = gtk_separator_menu_item_new();
+	gtk_widget_show(item);
+	gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item);
+
 	item = gtk_image_menu_item_new_with_mnemonic(_("H_ide Sidebar"));
 	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
 					  gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU));


Modified: projectorganizer/src/prjorg-utils.c
77 lines changed, 77 insertions(+), 0 deletions(-)
===================================================================
@@ -19,6 +19,11 @@
 #include <string.h>
 #include <glib.h>
 
+#include <glib/gstdio.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
 #include <geanyplugin.h>
 
 #include "prjorg-utils.h"
@@ -104,6 +109,78 @@ void open_file(gchar *utf8_name)
 }
 
 
+void close_file(gchar *utf8_name)
+{
+	GeanyDocument *doc = document_find_by_filename(utf8_name);
+
+	if (doc)
+	{
+		document_set_text_changed(doc, FALSE);
+		document_close(doc);
+	}
+}
+
+
+gboolean create_file(gchar *utf8_name)
+{
+	gchar *name = utils_get_locale_from_utf8(utf8_name);
+	gint fd = g_open(name, O_CREAT|O_EXCL, 0660);  // rw-rw----
+	gboolean success = FALSE;
+
+	if (fd != -1)
+	{
+		GError *err;
+		success = TRUE;
+		g_close(fd, &err);
+	}
+	g_free(name);
+	return success;
+}
+
+
+gboolean create_dir(char *utf8_name)
+{
+	gchar *name = utils_get_locale_from_utf8(utf8_name);
+	gboolean ret = g_mkdir_with_parents(name, 0770) == 0;  // rwxrwx---
+	g_free(name);
+	return ret;
+}
+
+
+gboolean remove_file_or_dir(char *utf8_name)
+{
+	gchar *name = utils_get_locale_from_utf8(utf8_name);
+	gboolean ret = g_remove(utf8_name) == 0;
+	g_free(name);
+	return ret;
+}
+
+
+static gboolean document_rename(GeanyDocument *document, gchar *utf8_name)
+{
+	// IMHO: this is wrong. If save as fails Geany's state becomes inconsistent.
+	document_rename_file(document, utf8_name);
+	return document_save_file_as(document, utf8_name);
+}
+
+
+gboolean rename_file_or_dir(gchar *utf8_oldname, gchar *utf8_newname)
+{
+	GeanyDocument *doc = document_find_by_filename(utf8_oldname);
+	if (doc)
+		return document_rename(doc, utf8_newname);
+	else
+	{
+		gchar *oldname = utils_get_locale_from_utf8(utf8_oldname);
+		gchar *newname = utils_get_locale_from_utf8(utf8_newname);
+		gint res = g_rename(oldname, newname);
+		g_free(oldname);
+		g_free(newname);
+		return res == 0;
+	}
+}
+
+
 gchar *get_selection(void)
 {
 	GeanyDocument *doc = document_get_current();


Modified: projectorganizer/src/prjorg-utils.h
7 lines changed, 7 insertions(+), 0 deletions(-)
===================================================================
@@ -25,6 +25,13 @@ gboolean patterns_match(GSList *patterns, const gchar *str);
 GSList *get_precompiled_patterns(gchar **patterns);
 
 void open_file(gchar *utf8_name);
+void close_file(gchar *utf8_name);
+
+gboolean create_file(char *utf8_name);
+gboolean create_dir(char *utf8_name);
+gboolean remove_file_or_dir(char *utf8_name);
+gboolean rename_file_or_dir(gchar *utf8_oldname, gchar *utf8_newname);
+
 gchar *get_selection(void);
 gchar *get_project_base_path(void);
 



--------------
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