📄 view_dir_tree.c
字号:
/* * GQview * (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! */#include "gqview.h"#include "view_dir_tree.h"#include "dnd.h"#include "dupe.h"#include "filelist.h"#include "layout.h"#include "layout_image.h"#include "layout_util.h"#include "utilops.h"#include "ui_bookmark.h"#include "ui_fileops.h"#include "ui_menu.h"#include "ui_tree_edit.h"#include <gdk/gdkkeysyms.h> /* for keyboard values */#define VDTREE_INDENT 14#define VDTREE_PAD 4enum { DIR_COLUMN_POINTER = 0, DIR_COLUMN_ICON, DIR_COLUMN_NAME, DIR_COLUMN_COLOR, DIR_COLUMN_COUNT};typedef struct _PathData PathData;struct _PathData{ gchar *name; FileData *node;};typedef struct _NodeData NodeData;struct _NodeData{ FileData *fd; gint expanded; time_t last_update;};static gint vdtree_populate_path_by_iter(ViewDirTree *vdt, GtkTreeIter *iter, gint force, const gchar *target_path);static FileData *vdtree_populate_path(ViewDirTree *vdt, const gchar *path, gint expand, gint force);/* *---------------------------------------------------------------------------- * utils *---------------------------------------------------------------------------- */static void set_cursor(GtkWidget *widget, GdkCursorType cursor_type){ GdkCursor *cursor = NULL; if (!widget || !widget->window) return; if (cursor_type > -1) cursor = gdk_cursor_new (cursor_type); gdk_window_set_cursor (widget->window, cursor); if (cursor) gdk_cursor_unref(cursor); gdk_flush();}static void vdtree_busy_push(ViewDirTree *vdt){ if (vdt->busy_ref == 0) set_cursor(vdt->treeview, GDK_WATCH); vdt->busy_ref++;}static void vdtree_busy_pop(ViewDirTree *vdt){ if (vdt->busy_ref == 1) set_cursor(vdt->treeview, -1); if (vdt->busy_ref > 0) vdt->busy_ref--;}static gint vdtree_find_row(ViewDirTree *vdt, FileData *fd, GtkTreeIter *iter, GtkTreeIter *parent){ GtkTreeModel *store; gint valid; store = gtk_tree_view_get_model(GTK_TREE_VIEW(vdt->treeview)); if (parent) { valid = gtk_tree_model_iter_children(store, iter, parent); } else { valid = gtk_tree_model_get_iter_first(store, iter); } while (valid) { NodeData *nd; GtkTreeIter found; gtk_tree_model_get(GTK_TREE_MODEL(store), iter, DIR_COLUMN_POINTER, &nd, -1); if (nd->fd == fd) return TRUE; if (vdtree_find_row(vdt, fd, &found, iter)) { memcpy(iter, &found, sizeof(found)); return TRUE; } valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), iter); } return FALSE;}static void vdtree_icon_set_by_iter(ViewDirTree *vdt, GtkTreeIter *iter, GdkPixbuf *pixbuf){ GtkTreeModel *store; GdkPixbuf *old; store = gtk_tree_view_get_model(GTK_TREE_VIEW(vdt->treeview)); gtk_tree_model_get(store, iter, DIR_COLUMN_ICON, &old, -1); if (old != vdt->pf->deny) { gtk_tree_store_set(GTK_TREE_STORE(store), iter, DIR_COLUMN_ICON, pixbuf, -1); }}static void vdtree_expand_by_iter(ViewDirTree *vdt, GtkTreeIter *iter, gint expand){ GtkTreeModel *store; GtkTreePath *tpath; store = gtk_tree_view_get_model(GTK_TREE_VIEW(vdt->treeview)); tpath = gtk_tree_model_get_path(store, iter); if (expand) { gtk_tree_view_expand_row(GTK_TREE_VIEW(vdt->treeview), tpath, FALSE); vdtree_icon_set_by_iter(vdt, iter, vdt->pf->open); } else { gtk_tree_view_collapse_row(GTK_TREE_VIEW(vdt->treeview), tpath); } gtk_tree_path_free(tpath);}static void vdtree_expand_by_data(ViewDirTree *vdt, FileData *fd, gint expand){ GtkTreeIter iter; if (vdtree_find_row(vdt, fd, &iter, NULL)) { vdtree_expand_by_iter(vdt, &iter, expand); }}static void vdtree_color_set(ViewDirTree *vdt, FileData *fd, gint color_set){ GtkTreeModel *store; GtkTreeIter iter; if (!vdtree_find_row(vdt, fd, &iter, NULL)) return; store = gtk_tree_view_get_model(GTK_TREE_VIEW(vdt->treeview)); gtk_tree_store_set(GTK_TREE_STORE(store), &iter, DIR_COLUMN_COLOR, color_set, -1);}static gint vdtree_rename_row_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data){ ViewDirTree *vdt = data; GtkTreeModel *store; GtkTreeIter iter; NodeData *nd; gchar *old_path; gchar *new_path; gchar *base; store = gtk_tree_view_get_model(GTK_TREE_VIEW(vdt->treeview)); if (!gtk_tree_model_get_iter(store, &iter, td->path)) return FALSE; gtk_tree_model_get(store, &iter, DIR_COLUMN_POINTER, &nd, -1); if (!nd) return FALSE; old_path = g_strdup(nd->fd->path); base = remove_level_from_path(old_path); new_path = concat_dir_and_file(base, new); g_free(base); if (file_util_rename_dir(old_path, new_path, vdt->treeview)) { vdtree_populate_path(vdt, new_path, TRUE, TRUE); if (vdt->layout && strcmp(vdt->path, old_path) == 0) { layout_set_path(vdt->layout, new_path); } } g_free(old_path); g_free(new_path); return FALSE;}static void vdtree_rename_by_data(ViewDirTree *vdt, FileData *fd){ GtkTreeModel *store; GtkTreePath *tpath; GtkTreeIter iter; if (!fd || !vdtree_find_row(vdt, fd, &iter, NULL)) return; store = gtk_tree_view_get_model(GTK_TREE_VIEW(vdt->treeview)); tpath = gtk_tree_model_get_path(store, &iter); tree_edit_by_path(GTK_TREE_VIEW(vdt->treeview), tpath, 0, fd->name, vdtree_rename_row_cb, vdt); gtk_tree_path_free(tpath);}static void vdtree_node_free(NodeData *nd){ if (!nd) return; file_data_free(nd->fd); g_free(nd);}static void vdtree_popup_destroy_cb(GtkWidget *widget, gpointer data){ ViewDirTree *vdt = data; vdtree_color_set(vdt, vdt->click_fd, FALSE); vdt->click_fd = NULL; vdt->popup = NULL; vdtree_color_set(vdt, vdt->drop_fd, FALSE); path_list_free(vdt->drop_list); vdt->drop_list = NULL; vdt->drop_fd = NULL;}/* *----------------------------------------------------------------------------- * drop menu (from dnd) *----------------------------------------------------------------------------- */static void vdtree_drop_menu_copy_cb(GtkWidget *widget, gpointer data){ ViewDirTree *vdt = data; const gchar *path; GList *list; if (!vdt->drop_fd) return; path = vdt->drop_fd->path; list = vdt->drop_list; vdt->drop_list = NULL; file_util_copy_simple(list, path);}static void vdtree_drop_menu_move_cb(GtkWidget *widget, gpointer data){ ViewDirTree *vdt = data; const gchar *path; GList *list; if (!vdt->drop_fd) return; path = vdt->drop_fd->path; list = vdt->drop_list; vdt->drop_list = NULL; file_util_move_simple(list, path);}static GtkWidget *vdtree_drop_menu(ViewDirTree *vdt, gint active){ GtkWidget *menu; menu = popup_menu_short_lived(); g_signal_connect(G_OBJECT(menu), "destroy", G_CALLBACK(vdtree_popup_destroy_cb), vdt); menu_item_add_stock_sensitive(menu, _("_Copy"), GTK_STOCK_COPY, active, G_CALLBACK(vdtree_drop_menu_copy_cb), vdt); menu_item_add_sensitive(menu, _("_Move"), active, G_CALLBACK(vdtree_drop_menu_move_cb), vdt); menu_item_add_divider(menu); menu_item_add_stock(menu, _("Cancel"), GTK_STOCK_CANCEL, NULL, vdt); return menu;}/* *----------------------------------------------------------------------------- * pop-up menu *----------------------------------------------------------------------------- */static void vdtree_pop_menu_up_cb(GtkWidget *widget, gpointer data){ ViewDirTree *vdt = data; gchar *path; if (!vdt->path || strcmp(vdt->path, "/") == 0) return; path = remove_level_from_path(vdt->path); if (vdt->select_func) { vdt->select_func(vdt, path, vdt->select_data); } g_free(path);}static void vdtree_pop_menu_slide_cb(GtkWidget *widget, gpointer data){ ViewDirTree *vdt = data; gchar *path; if (!vdt->layout) return; if (!vdt->click_fd) return; path = g_strdup(vdt->click_fd->path); layout_set_path(vdt->layout, path); layout_select_none(vdt->layout); layout_image_slideshow_stop(vdt->layout); layout_image_slideshow_start(vdt->layout); g_free(path);}static void vdtree_pop_menu_slide_rec_cb(GtkWidget *widget, gpointer data){ ViewDirTree *vdt = data; gchar *path; GList *list; if (!vdt->layout) return; if (!vdt->click_fd) return; path = g_strdup(vdt->click_fd->path); list = path_list_recursive(path); layout_image_slideshow_stop(vdt->layout); layout_image_slideshow_start_from_list(vdt->layout, list); g_free(path);}static void vdtree_pop_menu_dupe(ViewDirTree *vdt, gint recursive){ DupeWindow *dw; const gchar *path; GList *list = NULL; if (!vdt->click_fd) return; path = vdt->click_fd->path; if (recursive) { list = g_list_append(list, g_strdup(path)); } else { path_list(path, &list, NULL); list = path_list_filter(list, FALSE); } dw = dupe_window_new(DUPE_MATCH_NAME); dupe_window_add_files(dw, list, recursive); path_list_free(list);}static void vdtree_pop_menu_dupe_cb(GtkWidget *widget, gpointer data){ ViewDirTree *vdt = data; vdtree_pop_menu_dupe(vdt, FALSE);}static void vdtree_pop_menu_dupe_rec_cb(GtkWidget *widget, gpointer data){ ViewDirTree *vdt = data; vdtree_pop_menu_dupe(vdt, TRUE);}static void vdtree_pop_menu_new_cb(GtkWidget *widget, gpointer data){ ViewDirTree *vdt = data; const gchar *path; gchar *new_path; gchar *buf; if (!vdt->click_fd) return; path = vdt->click_fd->path; buf = concat_dir_and_file(path, _("new_folder")); new_path = unique_filename(buf, NULL, NULL, FALSE); g_free(buf); if (!new_path) return; if (!mkdir_utf8(new_path, 0755)) { gchar *text; text = g_strdup_printf(_("Unable to create folder:\n%s"), new_path); file_util_warning_dialog(_("Error creating folder"), text, GTK_STOCK_DIALOG_ERROR, vdt->treeview); g_free(text); } else { FileData *fd; fd = vdtree_populate_path(vdt, new_path, TRUE, TRUE); vdtree_rename_by_data(vdt, fd); } g_free(new_path);}static void vdtree_pop_menu_rename_cb(GtkWidget *widget, gpointer data){ ViewDirTree *vdt = data; vdtree_rename_by_data(vdt, vdt->click_fd);}static void vdtree_pop_menu_tree_cb(GtkWidget *widget, gpointer data){ ViewDirTree *vdt = data; if (vdt->layout) layout_views_set(vdt->layout, FALSE, vdt->layout->icon_view);}static void vdtree_pop_menu_refresh_cb(GtkWidget *widget, gpointer data){ ViewDirTree *vdt = data; if (vdt->layout) layout_refresh(vdt->layout);}static GtkWidget *vdtree_pop_menu(ViewDirTree *vdt, FileData *fd){ GtkWidget *menu; gint active; active = (fd != NULL); menu = popup_menu_short_lived(); g_signal_connect(G_OBJECT(menu), "destroy", G_CALLBACK(vdtree_popup_destroy_cb), vdt); menu_item_add_stock_sensitive(menu, _("_Up to parent"), GTK_STOCK_GO_UP, (vdt->path && strcmp(vdt->path, "/") != 0), G_CALLBACK(vdtree_pop_menu_up_cb), vdt); menu_item_add_divider(menu); menu_item_add_sensitive(menu, _("_Slideshow"), active, G_CALLBACK(vdtree_pop_menu_slide_cb), vdt); menu_item_add_sensitive(menu, _("Slideshow recursive"), active, G_CALLBACK(vdtree_pop_menu_slide_rec_cb), vdt); menu_item_add_divider(menu); menu_item_add_stock_sensitive(menu, _("Find _duplicates..."), GTK_STOCK_FIND, active, G_CALLBACK(vdtree_pop_menu_dupe_cb), vdt); menu_item_add_stock_sensitive(menu, _("Find duplicates recursive..."), GTK_STOCK_FIND, active, G_CALLBACK(vdtree_pop_menu_dupe_rec_cb), vdt); menu_item_add_divider(menu); active = (fd && access_file(fd->path, W_OK | X_OK)); menu_item_add_sensitive(menu, _("_New folder..."), active, G_CALLBACK(vdtree_pop_menu_new_cb), vdt); menu_item_add_sensitive(menu, _("_Rename..."), active, G_CALLBACK(vdtree_pop_menu_rename_cb), vdt); menu_item_add_divider(menu); menu_item_add_check(menu, _("View as _tree"), TRUE, G_CALLBACK(vdtree_pop_menu_tree_cb), vdt); menu_item_add_stock(menu, _("Re_fresh"), GTK_STOCK_REFRESH, G_CALLBACK(vdtree_pop_menu_refresh_cb), vdt); return menu;}/* *---------------------------------------------------------------------------- * dnd *---------------------------------------------------------------------------- */static GtkTargetEntry vdtree_dnd_drop_types[] = { { "text/uri-list", 0, TARGET_URI_LIST }};static gint vdtree_dnd_drop_types_count = 1;static void vdtree_dest_set(ViewDirTree *vdt, gint enable){ if (enable) { gtk_drag_dest_set(vdt->treeview, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, vdtree_dnd_drop_types, vdtree_dnd_drop_types_count, GDK_ACTION_MOVE | GDK_ACTION_COPY); } else { gtk_drag_dest_unset(vdt->treeview); }}static void vdtree_dnd_get(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time, gpointer data){ ViewDirTree *vdt = data; gchar *path; GList *list; gchar *uri_text = NULL; gint length = 0; if (!vdt->click_fd) return; path = vdt->click_fd->path; switch (info) { case TARGET_URI_LIST: case TARGET_TEXT_PLAIN: list = g_list_prepend(NULL, path); uri_text = uri_text_from_list(list, &length, (info == TARGET_TEXT_PLAIN)); g_list_free(list); break; } if (uri_text) { gtk_selection_data_set(selection_data, selection_data->target, 8, uri_text, length); g_free(uri_text); }}static void vdtree_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data){ ViewDirTree *vdt = data; vdtree_color_set(vdt, vdt->click_fd, TRUE); vdtree_dest_set(vdt, FALSE);}static void vdtree_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data){ ViewDirTree *vdt = data; vdtree_color_set(vdt, vdt->click_fd, FALSE); vdtree_dest_set(vdt, TRUE);}static void vdtree_dnd_drop_receive(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time, gpointer data)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -