📄 ui_pathsel.c
字号:
/* * (SLIK) SimpLIstic sKin functions * (C) 2004 John Ellis * * Author: John Ellis * * This software is released under the GNU General Public License (GNU GPL). * Please read the included file COPYING for more information. * This software comes with no warranty of any kind, use at your own risk! */#ifdef HAVE_CONFIG_H# include "config.h"#endif#include "intl.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <dirent.h>#include <fcntl.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <gtk/gtk.h>#include <gdk/gdkkeysyms.h> /* for key values */#include "ui_pathsel.h"#include "ui_bookmark.h"#include "ui_fileops.h"#include "ui_menu.h"#include "ui_misc.h"#include "ui_utildlg.h"#include "ui_tabcomp.h"#include "ui_tree_edit.h"#define DEST_WIDTH 250#define DEST_HEIGHT 210#define RENAME_PRESS_DELAY 333 /* 1/3 second, to allow double clicks */#define PATH_SEL_USE_HEADINGS FALSEenum { FILTER_COLUMN_NAME = 0, FILTER_COLUMN_FILTER};typedef struct _Dest_Data Dest_Data;struct _Dest_Data{ GtkWidget *d_view; GtkWidget *f_view; GtkWidget *entry; gchar *filter; gchar *path; GList *filter_list; GList *filter_text_list; GtkWidget *filter_combo; gint show_hidden; GtkWidget *hidden_button; GtkWidget *bookmark_list; GtkTreePath *right_click_path; void (*select_func)(const gchar *path, gpointer data); gpointer select_data; GenericDialog *gd; /* any open confirm dialogs ? */};typedef struct _DestDel_Data DestDel_Data;struct _DestDel_Data{ Dest_Data *dd; gchar *path;};static void dest_view_delete_dlg_cancel(GenericDialog *gd, gpointer data);/* *----------------------------------------------------------------------------- * (private) *----------------------------------------------------------------------------- */ static void dest_free_data(GtkWidget *widget, gpointer data){ Dest_Data *dd = data; if (dd->gd) { GenericDialog *gd = dd->gd; dest_view_delete_dlg_cancel(dd->gd, dd->gd->data); generic_dialog_close(gd); } if (dd->right_click_path) gtk_tree_path_free(dd->right_click_path); g_free(dd->filter); g_free(dd->path); g_free(dd);}static gint dest_check_filter(const gchar *filter, const gchar *file){ const gchar *f_ptr = filter; const gchar *strt_ptr; gint i; gint l; l = strlen(file); if (filter[0] == '*') return TRUE; while (f_ptr < filter + strlen(filter)) { strt_ptr = f_ptr; i=0; while (*f_ptr != ';' && *f_ptr != '\0') { f_ptr++; i++; } if (*f_ptr != '\0' && f_ptr[1] == ' ') f_ptr++; /* skip space immediately after separator */ f_ptr++; if (l >= i && strncasecmp(file + l - i, strt_ptr, i) == 0) return TRUE; } return FALSE;}#ifndef CASE_SORT#define CASE_SORT strcmp#endifstatic gint dest_sort_cb(void *a, void *b){ return CASE_SORT((gchar *)a, (gchar *)b);}static gint is_hidden(const gchar *name){ if (name[0] != '.') return FALSE; if (name[1] == '\0') return FALSE; if (name[1] == '.' && name[2] == '\0') return FALSE; return TRUE;}static void dest_populate(Dest_Data *dd, const gchar *path){ DIR *dp; struct dirent *dir; struct stat ent_sbuf; GList *path_list = NULL; GList *file_list = NULL; GList *list; GtkListStore *store; gchar *pathl; if (!path) return; pathl = path_from_utf8(path); dp = opendir(pathl); if (!dp) { /* dir not found */ g_free(pathl); return; } while ((dir = readdir(dp)) != NULL) { /* skips removed files */ if (dir->d_ino > 0 && (dd->show_hidden || !is_hidden(dir->d_name)) ) { gchar *name = dir->d_name; gchar *filepath = g_strconcat(pathl, "/", name, NULL); if (stat(filepath, &ent_sbuf) >= 0 && S_ISDIR(ent_sbuf.st_mode)) { path_list = g_list_prepend(path_list, path_to_utf8(name)); } else if (dd->f_view) { if (!dd->filter || (dd->filter && dest_check_filter(dd->filter, name))) file_list = g_list_prepend(file_list, path_to_utf8(name)); } g_free(filepath); } } closedir(dp); g_free(pathl); path_list = g_list_sort(path_list, (GCompareFunc) dest_sort_cb); file_list = g_list_sort(file_list, (GCompareFunc) dest_sort_cb); store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(dd->d_view))); gtk_list_store_clear(store); list = path_list; while (list) { GtkTreeIter iter; gchar *filepath; if (strcmp(list->data, ".") == 0) { filepath = g_strdup(path); } else if (strcmp(list->data, "..") == 0) { gchar *p; filepath = g_strdup(path); p = (gchar *)filename_from_path(filepath); if (p - 1 != filepath) p--; p[0] = '\0'; } else { filepath = concat_dir_and_file(path, list->data); } gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, list->data, 1, filepath, -1); g_free(filepath); list = list->next; } path_list_free(path_list); if (dd->f_view) { store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(dd->f_view))); gtk_list_store_clear(store); list = file_list; while (list) { GtkTreeIter iter; gchar *filepath; const gchar *name = list->data; filepath = concat_dir_and_file(path, name); gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, name, 1, filepath, -1); g_free(filepath); list = list->next; } path_list_free(file_list); } g_free(dd->path); dd->path = g_strdup(path);}static void dest_change_dir(Dest_Data *dd, const gchar *path, gint retain_name){ gchar *old_name = NULL; gint s = 0; if (retain_name) { const gchar *buf = gtk_entry_get_text(GTK_ENTRY(dd->entry)); if (!isdir(buf)) { if (path && strcmp(path, "/") == 0) { old_name = g_strdup(filename_from_path(buf)); } else { old_name = g_strconcat("/", filename_from_path(buf), NULL); s = 1; } } } gtk_entry_set_text(GTK_ENTRY(dd->entry), path); dest_populate(dd, path); /* remember filename */ if (old_name) { gint pos = -1; gtk_editable_insert_text(GTK_EDITABLE(dd->entry), old_name, -1, &pos); gtk_editable_select_region(GTK_EDITABLE(dd->entry), strlen(path) + s, strlen(path) + strlen(old_name)); g_free(old_name); }}/* *----------------------------------------------------------------------------- * drag and drop *----------------------------------------------------------------------------- */enum { TARGET_URI_LIST, TARGET_TEXT_PLAIN};static GtkTargetEntry dest_drag_types[] = { { "text/uri-list", 0, TARGET_URI_LIST }, { "text/plain", 0, TARGET_TEXT_PLAIN }};#define dest_drag_types_n 2static void dest_dnd_set_data(GtkWidget *view, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time, gpointer data){ gchar *path = NULL; gchar *uri_text = NULL; GList *list = NULL; gint length = 0; GtkTreeModel *model; GtkTreeSelection *selection; GtkTreeIter iter; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); if (!gtk_tree_selection_get_selected(selection, &model, &iter)) return; gtk_tree_model_get(model, &iter, 1, &path, -1); if (!path) return; list = g_list_append(list, path); switch (info) { case TARGET_URI_LIST: uri_text = uri_text_from_list(list, &length, FALSE); break; case TARGET_TEXT_PLAIN: uri_text = uri_text_from_list(list, &length, TRUE); break; } path_list_free(list); if (!uri_text) return; gtk_selection_data_set(selection_data, selection_data->target, 8, uri_text, length); g_free(uri_text);}static void dest_dnd_init(Dest_Data *dd){ gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(dd->d_view), GDK_BUTTON1_MASK, dest_drag_types, dest_drag_types_n, GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK); g_signal_connect(G_OBJECT(dd->d_view), "drag_data_get", G_CALLBACK(dest_dnd_set_data), dd); if (dd->f_view) { gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(dd->f_view), GDK_BUTTON1_MASK, dest_drag_types, dest_drag_types_n, GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK); g_signal_connect(G_OBJECT(dd->f_view), "drag_data_get", G_CALLBACK(dest_dnd_set_data), dd); }}/* *----------------------------------------------------------------------------- * destination widget file management utils *----------------------------------------------------------------------------- */static void dest_view_store_selection(Dest_Data *dd, GtkTreeView *view){ GtkTreeModel *model; GtkTreeSelection *selection; GtkTreeIter iter; if (dd->right_click_path) gtk_tree_path_free(dd->right_click_path); dd->right_click_path = NULL; selection = gtk_tree_view_get_selection(view); if (!gtk_tree_selection_get_selected(selection, &model, &iter)) { return; } dd->right_click_path = gtk_tree_model_get_path(model, &iter);}static gint dest_view_rename_cb(TreeEditData *ted, const gchar *old, const gchar *new, gpointer data){ Dest_Data *dd = data; GtkTreeModel *model; GtkTreeIter iter; gchar *buf; gchar *old_path; gchar *new_path; model = gtk_tree_view_get_model(GTK_TREE_VIEW(ted->tree)); gtk_tree_model_get_iter(model, &iter, dd->right_click_path); gtk_tree_model_get(model, &iter, 1, &old_path, -1); if (!old_path) return FALSE; buf = remove_level_from_path(old_path); new_path = concat_dir_and_file(buf, new); g_free(buf); if (isname(new_path)) { buf = g_strdup_printf(_("A file with name %s already exists."), new); warning_dialog("Rename failed", buf, GTK_STOCK_DIALOG_INFO, dd->entry); g_free(buf); } else if (!rename_file(old_path, new_path)) { buf = g_strdup_printf(_("Failed to rename %s to %s."), old, new); warning_dialog("Rename failed", buf, GTK_STOCK_DIALOG_ERROR, dd->entry); g_free(buf); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -