[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