Branch: refs/heads/master Author: Frank Lanitz frank@frank.uvena.de Committer: GitHub noreply@github.com Date: Sat, 03 Feb 2018 13:39:48 UTC Commit: 5677bf157780ade4850108e4e00e2538c5e8ac7a https://github.com/geany/geany-plugins/commit/5677bf157780ade4850108e4e00e25...
Log Message: ----------- Merge pull request #681 from LarsGit223/wb-fileops2
workbench: added "Create file here..."/"Create directory here..."
Modified Paths: -------------- utils/src/filelist.c utils/src/filelist.h workbench/README workbench/src/dialogs.c workbench/src/dialogs.h workbench/src/plugin_main.c workbench/src/popup_menu.c workbench/src/sidebar.c workbench/src/wb_project.c
Modified: utils/src/filelist.c 83 lines changed, 80 insertions(+), 3 deletions(-) =================================================================== @@ -88,7 +88,7 @@ static gboolean filelist_patterns_match(GSList *patterns, const gchar *str)
/* Scan directory searchdir. Input and output parameters come from/go to params. */ -static void filelist_scan_directory_int(const gchar *searchdir, ScanDirParams *params) +static void filelist_scan_directory_int(const gchar *searchdir, ScanDirParams *params, guint flags) { GDir *dir; gchar *locale_path = utils_get_locale_from_utf8(searchdir); @@ -115,7 +115,9 @@ static void filelist_scan_directory_int(const gchar *searchdir, ScanDirParams *p
locale_name = g_dir_read_name(dir); if (!locale_name) + { break; + }
utf8_name = utils_get_utf8_from_locale(locale_name); locale_filename = g_build_filename(locale_path, locale_name, NULL); @@ -125,8 +127,12 @@ static void filelist_scan_directory_int(const gchar *searchdir, ScanDirParams *p { if (!filelist_patterns_match(params->ignored_dirs_list, utf8_name)) { - filelist_scan_directory_int(utf8_filename, params); + filelist_scan_directory_int(utf8_filename, params, flags); params->folder_count++; + if (flags & FILELIST_FLAG_ADD_DIRS) + { + params->filelist = g_slist_prepend(params->filelist, g_strdup(utf8_filename)); + } } } else if (g_file_test(locale_filename, G_FILE_TEST_IS_REGULAR)) @@ -190,7 +196,78 @@ GSList *gp_filelist_scan_directory(guint *files, guint *folders, const gchar *se params.ignored_file_list = filelist_get_precompiled_patterns(ignored_file_patterns);
params.visited_paths = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); - filelist_scan_directory_int(searchdir, ¶ms); + filelist_scan_directory_int(searchdir, ¶ms, 0); + g_hash_table_destroy(params.visited_paths); + + g_slist_foreach(params.file_patterns, (GFunc) g_pattern_spec_free, NULL); + g_slist_free(params.file_patterns); + + g_slist_foreach(params.ignored_dirs_list, (GFunc) g_pattern_spec_free, NULL); + g_slist_free(params.ignored_dirs_list); + + g_slist_foreach(params.ignored_file_list, (GFunc) g_pattern_spec_free, NULL); + g_slist_free(params.ignored_file_list); + + if (files != NULL) + { + *files = params.file_count; + } + if (folders != NULL) + { + *folders = params.folder_count; + } + + return params.filelist; +} + + +/** Scan a directory and return a list of files and directories. + * + * The function scans directory searchdir and returns a list of files. + * The list will only include files which match the patterns in file_patterns. + * Directories or files matched by ignored_dirs_patterns or ignored_file_patterns + * will not be scanned or added to the list. + * + * If flags is 0 then the result will be the same as for gp_filelist_scan_directory(). + * + * @param files Can be optionally specified to return the number of matched/found + * files in *files. + * @param folders Can be optionally specified to return the number of matched/found + * folders/sub-directories in *folders. + * @param searchdir Directory which shall be scanned + * @param file_patterns + * File patterns for matching files (e.g. "*.c") or NULL + * for all files. + * @param ignored_dirs_patterns + * Patterns for ignored directories + * @param ignored_file_patterns + * Patterns for ignored files + * @param flags Flags which influence the returned list: + * - FILELIST_FLAG_ADD_DIRS: if set, directories will be added + * as own list entries. This also includes empty dirs. + * @return GSList of matched files + * + **/ +GSList *gp_filelist_scan_directory_full(guint *files, guint *folders, const gchar *searchdir, gchar **file_patterns, + gchar **ignored_dirs_patterns, gchar **ignored_file_patterns, guint flags) +{ + ScanDirParams params = { 0 }; + + if (!file_patterns || !file_patterns[0]) + { + const gchar *all_pattern[] = { "*", NULL }; + params.file_patterns = filelist_get_precompiled_patterns((gchar **)all_pattern); + } + else + { + params.file_patterns = filelist_get_precompiled_patterns(file_patterns); + } + + params.ignored_dirs_list = filelist_get_precompiled_patterns(ignored_dirs_patterns); + params.ignored_file_list = filelist_get_precompiled_patterns(ignored_file_patterns); + + params.visited_paths = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + filelist_scan_directory_int(searchdir, ¶ms, flags); g_hash_table_destroy(params.visited_paths);
g_slist_foreach(params.file_patterns, (GFunc) g_pattern_spec_free, NULL);
Modified: utils/src/filelist.h 7 lines changed, 7 insertions(+), 0 deletions(-) =================================================================== @@ -23,8 +23,15 @@
G_BEGIN_DECLS
+typedef enum +{ + FILELIST_FLAG_ADD_DIRS = 1, +}FILELIST_FLAG; + GSList *gp_filelist_scan_directory(guint *files, guint *folders, const gchar *searchdir, gchar **file_patterns, gchar **ignored_dirs_patterns, gchar **ignored_file_patterns); +GSList *gp_filelist_scan_directory_full(guint *files, guint *folders, const gchar *searchdir, gchar **file_patterns, + gchar **ignored_dirs_patterns, gchar **ignored_file_patterns, guint flags);
G_END_DECLS
Modified: workbench/README 8 lines changed, 8 insertions(+), 0 deletions(-) =================================================================== @@ -133,6 +133,14 @@ These are the available items: Remove file from the Workbench or project bookmarks. It is only available if you right clicked on a bookmark.
+**Create file here...** + Select this item to create a new file at the current selected position + in the file tree. Available since version 1.02 of the workbench plugin. + +**Create directory here...** + Select this item to create a new directory at the current selected position + in the file tree. Available since version 1.02 of the workbench plugin. + Known issues ============
Modified: workbench/src/dialogs.c 71 lines changed, 71 insertions(+), 0 deletions(-) =================================================================== @@ -28,6 +28,77 @@
extern GeanyPlugin *geany_plugin;
+ +/** Shows the dialog "Create new file". + * + * The dialog lets the user create a new file (filter *). + * + * @param path The current folder + * @return The filename + * + **/ +gchar *dialogs_create_new_file(const gchar *path) +{ + gchar *filename = NULL; + GtkWidget *dialog; + + dialog = gtk_file_chooser_dialog_new(_("Create new file"), + GTK_WINDOW(wb_globals.geany_plugin->geany_data->main_widgets->window), GTK_FILE_CHOOSER_ACTION_SAVE, + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("C_reate"), GTK_RESPONSE_ACCEPT, NULL); + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); + + if (path != NULL) + { + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path); + } + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + } + + gtk_widget_destroy(dialog); + + return filename; +} + + +/** Shows the dialog "Create new directory". + * + * The dialog lets the user create a new directory. + * + * @param path The current folder + * @return The filename + * + **/ +gchar *dialogs_create_new_directory(const gchar *path) +{ + gchar *filename = NULL; + GtkWidget *dialog; + + dialog = gtk_file_chooser_dialog_new(_("Create new directory"), + GTK_WINDOW(wb_globals.geany_plugin->geany_data->main_widgets->window), GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER, + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("C_reate"), GTK_RESPONSE_ACCEPT, NULL); + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); + + if (path != NULL) + { + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path); + } + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + } + + gtk_widget_destroy(dialog); + + return filename; +} + + /** Shows the dialog "Create new workbench". * * The dialog lets the user create a new workbench file (filter *.geanywb).
Modified: workbench/src/dialogs.h 2 lines changed, 2 insertions(+), 0 deletions(-) =================================================================== @@ -19,6 +19,8 @@ #ifndef __WB_DIALOGS_H__ #define __WB_DIALOGS_H__
+gchar *dialogs_create_new_file(const gchar *path); +gchar *dialogs_create_new_directory(const gchar *path); gchar *dialogs_create_new_workbench(void); gchar *dialogs_open_workbench(void); gchar *dialogs_add_project(void);
Modified: workbench/src/plugin_main.c 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -128,7 +128,7 @@ void geany_load_module(GeanyPlugin *plugin) /* Set metadata */ plugin->info->name = _("Workbench"); plugin->info->description = _("Manage and customize multiple projects."); - plugin->info->version = "1.01"; + plugin->info->version = "1.02"; plugin->info->author = "LarsGit223";
/* Set functions */
Modified: workbench/src/popup_menu.c 114 lines changed, 114 insertions(+), 0 deletions(-) =================================================================== @@ -19,9 +19,12 @@ /* * Code for the popup menu. */ +#include <errno.h> #include <sys/time.h> #include <gdk/gdkkeysyms.h> #include <string.h> +#include <glib.h> +#include <glib/gstdio.h>
#ifdef HAVE_CONFIG_H #include "config.h" @@ -57,6 +60,8 @@ static struct GtkWidget *add_wb_bookmark; GtkWidget *add_prj_bookmark; GtkWidget *remove_bookmark; + GtkWidget *new_file; + GtkWidget *new_directory; } s_popup_menu;
@@ -91,6 +96,8 @@ void popup_menu_show(POPUP_CONTEXT context, GdkEventButton *event) gtk_widget_set_sensitive (s_popup_menu.remove_bookmark, FALSE); gtk_widget_set_sensitive (s_popup_menu.subdir_open_all, FALSE); gtk_widget_set_sensitive (s_popup_menu.subdir_close_all, FALSE); + gtk_widget_set_sensitive (s_popup_menu.new_file, FALSE); + gtk_widget_set_sensitive (s_popup_menu.new_directory, FALSE); break; case POPUP_CONTEXT_DIRECTORY: gtk_widget_set_sensitive (s_popup_menu.add_project, TRUE); @@ -110,6 +117,8 @@ void popup_menu_show(POPUP_CONTEXT context, GdkEventButton *event) gtk_widget_set_sensitive (s_popup_menu.remove_bookmark, FALSE); gtk_widget_set_sensitive (s_popup_menu.subdir_open_all, FALSE); gtk_widget_set_sensitive (s_popup_menu.subdir_close_all, FALSE); + gtk_widget_set_sensitive (s_popup_menu.new_file, TRUE); + gtk_widget_set_sensitive (s_popup_menu.new_directory, TRUE); break; case POPUP_CONTEXT_SUB_DIRECTORY: gtk_widget_set_sensitive (s_popup_menu.add_project, TRUE); @@ -129,6 +138,8 @@ void popup_menu_show(POPUP_CONTEXT context, GdkEventButton *event) gtk_widget_set_sensitive (s_popup_menu.remove_bookmark, FALSE); gtk_widget_set_sensitive (s_popup_menu.subdir_open_all, TRUE); gtk_widget_set_sensitive (s_popup_menu.subdir_close_all, TRUE); + gtk_widget_set_sensitive (s_popup_menu.new_file, TRUE); + gtk_widget_set_sensitive (s_popup_menu.new_directory, TRUE); break; case POPUP_CONTEXT_FILE: gtk_widget_set_sensitive (s_popup_menu.add_project, TRUE); @@ -148,6 +159,8 @@ void popup_menu_show(POPUP_CONTEXT context, GdkEventButton *event) gtk_widget_set_sensitive (s_popup_menu.remove_bookmark, FALSE); gtk_widget_set_sensitive (s_popup_menu.subdir_open_all, TRUE); gtk_widget_set_sensitive (s_popup_menu.subdir_close_all, TRUE); + gtk_widget_set_sensitive (s_popup_menu.new_file, TRUE); + gtk_widget_set_sensitive (s_popup_menu.new_directory, TRUE); break; case POPUP_CONTEXT_BACKGROUND: gtk_widget_set_sensitive (s_popup_menu.add_project, TRUE); @@ -167,6 +180,8 @@ void popup_menu_show(POPUP_CONTEXT context, GdkEventButton *event) gtk_widget_set_sensitive (s_popup_menu.remove_bookmark, FALSE); gtk_widget_set_sensitive (s_popup_menu.subdir_open_all, FALSE); gtk_widget_set_sensitive (s_popup_menu.subdir_close_all, FALSE); + gtk_widget_set_sensitive (s_popup_menu.new_file, FALSE); + gtk_widget_set_sensitive (s_popup_menu.new_directory, FALSE); break; case POPUP_CONTEXT_WB_BOOKMARK: gtk_widget_set_sensitive (s_popup_menu.add_project, TRUE); @@ -186,6 +201,8 @@ void popup_menu_show(POPUP_CONTEXT context, GdkEventButton *event) gtk_widget_set_sensitive (s_popup_menu.remove_bookmark, TRUE); gtk_widget_set_sensitive (s_popup_menu.subdir_open_all, FALSE); gtk_widget_set_sensitive (s_popup_menu.subdir_close_all, FALSE); + gtk_widget_set_sensitive (s_popup_menu.new_file, FALSE); + gtk_widget_set_sensitive (s_popup_menu.new_directory, FALSE); break; case POPUP_CONTEXT_PRJ_BOOKMARK: gtk_widget_set_sensitive (s_popup_menu.add_project, TRUE); @@ -205,6 +222,8 @@ void popup_menu_show(POPUP_CONTEXT context, GdkEventButton *event) gtk_widget_set_sensitive (s_popup_menu.remove_bookmark, TRUE); gtk_widget_set_sensitive (s_popup_menu.subdir_open_all, FALSE); gtk_widget_set_sensitive (s_popup_menu.subdir_close_all, FALSE); + gtk_widget_set_sensitive (s_popup_menu.new_file, FALSE); + gtk_widget_set_sensitive (s_popup_menu.new_directory, FALSE); break; } gtk_menu_popup(GTK_MENU(s_popup_menu.widget), NULL, NULL, NULL, NULL, @@ -506,6 +525,85 @@ static void popup_menu_on_subdir_close_all (G_GNUC_UNUSED GtkMenuItem *menuitem, }
+/* Handle popup menu item "Create new file here..." */ +static void popup_menu_on_new_file(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + gchar *filename, *path = NULL, *abs_path = NULL; + SIDEBAR_CONTEXT context; + + if (sidebar_file_view_get_selected_context(&context)) + { + if (context.subdir != NULL) + { + path = context.subdir; + abs_path = g_strdup(path); + } + else + { + path = wb_project_dir_get_base_dir(context.directory); + abs_path = get_combined_path(wb_project_get_filename(context.project), path); + } + } + + filename = dialogs_create_new_file(abs_path); + if (filename == NULL) + { + return; + } + else if (!g_file_test (filename, G_FILE_TEST_EXISTS)) + { + FILE *new_file; + new_file = g_fopen (filename, "w"); + if (new_file == NULL) + { + dialogs_show_msgbox(GTK_MESSAGE_ERROR, _("Could not create new file "%s":\n\n%s"), filename, strerror(errno)); + } + else + { + fclose(new_file); + wb_project_dir_rescan(context.project, context.directory); + sidebar_update(SIDEBAR_CONTEXT_DIRECTORY_RESCANNED, &context); + document_open_file(filename, FALSE, NULL, NULL); + } + } + + g_free(abs_path); + g_free(filename); +} + + +/* Handle popup menu item "Create new directory here..." */ +static void popup_menu_on_new_directory(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + gchar *filename, *path = NULL, *abs_path = NULL; + SIDEBAR_CONTEXT context; + + if (sidebar_file_view_get_selected_context(&context)) + { + if (context.subdir != NULL) + { + path = context.subdir; + abs_path = g_strdup(path); + } + else + { + path = wb_project_dir_get_base_dir(context.directory); + abs_path = get_combined_path(wb_project_get_filename(context.project), path); + } + } + + filename = dialogs_create_new_directory(abs_path); + if (filename != NULL) + { + wb_project_dir_rescan(context.project, context.directory); + sidebar_update(SIDEBAR_CONTEXT_DIRECTORY_RESCANNED, &context); + } + + g_free(abs_path); + g_free(filename); +} + + /** Setup/Initialize the popup menu. * **/ @@ -650,4 +748,20 @@ void popup_menu_init(void) gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_remove_from_bookmarks), NULL); s_popup_menu.remove_bookmark = item; + + item = gtk_separator_menu_item_new(); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + + item = gtk_menu_item_new_with_mnemonic(_("_Create file here...")); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_new_file), NULL); + s_popup_menu.new_file = item; + + item = gtk_menu_item_new_with_mnemonic(_("_Create directory here...")); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_new_directory), NULL); + s_popup_menu.new_directory = item; }
Modified: workbench/src/sidebar.c 44 lines changed, 38 insertions(+), 6 deletions(-) =================================================================== @@ -96,7 +96,7 @@ static void sidebar_create_branch(gint level, const gchar *abs_base_dir, GSList GSList *dir_list = NULL; GSList *file_list = NULL; GSList *elem = NULL; - gchar **path_arr; + gchar **path_arr, *part, *full, *dirpath;
foreach_slist (elem, leaf_list) { @@ -105,21 +105,35 @@ static void sidebar_create_branch(gint level, const gchar *abs_base_dir, GSList continue; } path_arr = elem->data; + if (path_arr[level] == NULL) + { + continue; + }
if (path_arr[level+1] != NULL) { dir_list = g_slist_prepend(dir_list, path_arr); } else { - file_list = g_slist_prepend(file_list, path_arr); + // Extra check for empty directories + part = g_build_filenamev(path_arr); + dirpath = g_build_filename(abs_base_dir, part, NULL); + if (dirpath != NULL && g_file_test (dirpath, G_FILE_TEST_IS_DIR)) + { + dir_list = g_slist_prepend(dir_list, path_arr); + g_free(dirpath); + } + else + { + file_list = g_slist_prepend(file_list, path_arr); + } } }
foreach_slist (elem, file_list) { GtkTreeIter iter; - gchar *part, *full; GIcon *icon = NULL;
path_arr = elem->data; @@ -177,6 +191,10 @@ static void sidebar_create_branch(gint level, const gchar *abs_base_dir, GSList { gboolean dir_changed;
+ part = g_build_filenamev(path_arr); + full = g_build_filename(abs_base_dir, part, NULL); + g_free(part); + path_arr = (gchar **) elem->data; dir_changed = g_strcmp0(last_dir_name, path_arr[level]) != 0;
@@ -186,6 +204,7 @@ static void sidebar_create_branch(gint level, const gchar *abs_base_dir, GSList FILEVIEW_COLUMN_ICON, icon_dir, FILEVIEW_COLUMN_NAME, last_dir_name, FILEVIEW_COLUMN_DATA_ID, DATA_ID_SUB_DIRECTORY, + FILEVIEW_COLUMN_ASSIGNED_DATA_POINTER, g_strdup(full), -1);
sidebar_create_branch(level+1, abs_base_dir, tmp_list, &iter); @@ -194,15 +213,22 @@ static void sidebar_create_branch(gint level, const gchar *abs_base_dir, GSList tmp_list = NULL; last_dir_name = path_arr[level]; } + g_free(full);
tmp_list = g_slist_prepend(tmp_list, path_arr); }
+ part = g_build_filenamev(path_arr); + full = g_build_filename(abs_base_dir, part, NULL); + g_free(part); + gtk_tree_store_insert_with_values(sidebar.file_store, &iter, parent, 0, FILEVIEW_COLUMN_ICON, icon_dir, FILEVIEW_COLUMN_NAME, last_dir_name, FILEVIEW_COLUMN_DATA_ID, DATA_ID_SUB_DIRECTORY, + FILEVIEW_COLUMN_ASSIGNED_DATA_POINTER, g_strdup(full), -1); + g_free(full);
sidebar_create_branch(level+1, abs_base_dir, tmp_list, &iter);
@@ -221,7 +247,7 @@ static void sidebar_create_branch(gint level, const gchar *abs_base_dir, GSList /* Reverse strcmp */ static int rev_strcmp(const char *str1, const char *str2) { - return strcmp(str2, str1); + return g_strcmp0(str2, str1); }
@@ -241,7 +267,10 @@ static void sidebar_insert_project_directory(WB_PROJECT *prj, WB_PROJECT_DIR *di while (g_hash_table_iter_next(&iter, &key, &value)) { gchar *path = get_relative_path(abs_base_dir, key); - lst = g_slist_prepend(lst, path); + if (path != NULL) + { + lst = g_slist_prepend(lst, path); + } } /* sort in reverse order so we can prepend nodes to the tree store - * the store behaves as a linked list and prepending is faster */ @@ -961,7 +990,10 @@ gboolean sidebar_file_view_get_selected_context(SIDEBAR_CONTEXT *context) /* Has not got any data. */ break; case DATA_ID_SUB_DIRECTORY: - context->subdir = data; + if (context->subdir == NULL) + { + context->subdir = data; + } break; case DATA_ID_FILE: context->file = data;
Modified: workbench/src/wb_project.c 5 lines changed, 3 insertions(+), 2 deletions(-) =================================================================== @@ -528,8 +528,9 @@ static guint wb_project_dir_rescan_int(WB_PROJECT *prj, WB_PROJECT_DIR *root) searchdir = get_combined_path(prj->filename, root->base_dir); root->file_count = 0; root->subdir_count = 0; - lst = gp_filelist_scan_directory(&(root->file_count), &(root->subdir_count), - searchdir, file_patterns, root->ignored_dirs_patterns, root->ignored_file_patterns); + lst = gp_filelist_scan_directory_full(&(root->file_count), &(root->subdir_count), + searchdir, file_patterns, root->ignored_dirs_patterns, root->ignored_file_patterns, + FILELIST_FLAG_ADD_DIRS); g_free(searchdir);
foreach_slist(elem, lst)
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).