📄 view_dir_tree.c
字号:
{ ViewDirTree *vdt = data; GtkTreePath *tpath; GtkTreeIter iter; FileData *fd = NULL; vdt->click_fd = NULL; if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), x, y, &tpath, NULL, NULL, NULL)) { GtkTreeModel *store; NodeData *nd; store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); gtk_tree_model_get_iter(store, &iter, tpath); gtk_tree_model_get(store, &iter, DIR_COLUMN_POINTER, &nd, -1); gtk_tree_path_free(tpath); fd = (nd) ? nd->fd : NULL; } if (!fd) return; if (info == TARGET_URI_LIST) { GList *list; gint active; list = uri_list_from_text(selection_data->data, TRUE); if (!list) return; active = access_file(fd->path, W_OK | X_OK); vdtree_color_set(vdt, fd, TRUE); vdt->popup = vdtree_drop_menu(vdt, active); gtk_menu_popup(GTK_MENU(vdt->popup), NULL, NULL, NULL, NULL, 0, time); vdt->drop_fd = fd; vdt->drop_list = list; }}static gint vdtree_dnd_drop_expand_cb(gpointer data){ ViewDirTree *vdt = data; GtkTreeIter iter; if (vdt->drop_fd && vdtree_find_row(vdt, vdt->drop_fd, &iter, NULL)) { vdtree_populate_path_by_iter(vdt, &iter, FALSE, vdt->path); vdtree_expand_by_data(vdt, vdt->drop_fd, TRUE); } vdt->drop_expand_id = -1; return FALSE;}static void vdtree_dnd_drop_expand_cancel(ViewDirTree *vdt){ if (vdt->drop_expand_id != -1) g_source_remove(vdt->drop_expand_id); vdt->drop_expand_id = -1;}static void vdtree_dnd_drop_expand(ViewDirTree *vdt){ vdtree_dnd_drop_expand_cancel(vdt); vdt->drop_expand_id = g_timeout_add(1000, vdtree_dnd_drop_expand_cb, vdt);}static void vdtree_drop_update(ViewDirTree *vdt, gint x, gint y){ GtkTreePath *tpath; GtkTreeIter iter; FileData *fd = NULL; if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vdt->treeview), x, y, &tpath, NULL, NULL, NULL)) { GtkTreeModel *store; NodeData *nd; store = gtk_tree_view_get_model(GTK_TREE_VIEW(vdt->treeview)); gtk_tree_model_get_iter(store, &iter, tpath); gtk_tree_model_get(store, &iter, DIR_COLUMN_POINTER, &nd, -1); gtk_tree_path_free(tpath); fd = (nd) ? nd->fd : NULL; } if (fd != vdt->drop_fd) { vdtree_color_set(vdt, vdt->drop_fd, FALSE); vdtree_color_set(vdt, fd, TRUE); if (fd) vdtree_dnd_drop_expand(vdt); } vdt->drop_fd = fd;}static void vdtree_dnd_drop_scroll_cancel(ViewDirTree *vdt){ if (vdt->drop_scroll_id != -1) g_source_remove(vdt->drop_scroll_id); vdt->drop_scroll_id = -1;}static gint vdtree_auto_scroll_idle_cb(gpointer data){ ViewDirTree *vdt = data; if (vdt->drop_fd) { GdkWindow *window; gint x, y; gint w, h; window = vdt->treeview->window; gdk_window_get_pointer(window, &x, &y, NULL); gdk_drawable_get_size(window, &w, &h); if (x >= 0 && x < w && y >= 0 && y < h) { vdtree_drop_update(vdt, x, y); } } vdt->drop_scroll_id = -1; return FALSE;}static gint vdtree_auto_scroll_notify_cb(GtkWidget *widget, gint x, gint y, gpointer data){ ViewDirTree *vdt = data; if (!vdt->drop_fd || vdt->drop_list) return FALSE; if (vdt->drop_scroll_id == -1) vdt->drop_scroll_id = g_idle_add(vdtree_auto_scroll_idle_cb, vdt); return TRUE;}static gint vdtree_dnd_drop_motion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, gpointer data){ ViewDirTree *vdt = data; vdt->click_fd = NULL; if (gtk_drag_get_source_widget(context) == vdt->treeview) { gdk_drag_status(context, 0, time); return TRUE; } else { gdk_drag_status(context, context->suggested_action, time); } vdtree_drop_update(vdt, x, y); if (vdt->drop_fd) { GtkAdjustment *adj = gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(vdt->treeview)); widget_auto_scroll_start(vdt->treeview, adj, -1, -1, vdtree_auto_scroll_notify_cb, vdt); } return FALSE;}static void vdtree_dnd_drop_leave(GtkWidget *widget, GdkDragContext *context, guint time, gpointer data){ ViewDirTree *vdt = data; if (vdt->drop_fd != vdt->click_fd) vdtree_color_set(vdt, vdt->drop_fd, FALSE); vdt->drop_fd = NULL; vdtree_dnd_drop_expand_cancel(vdt);}static void vdtree_dnd_init(ViewDirTree *vdt){ gtk_drag_source_set(vdt->treeview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, dnd_file_drag_types, dnd_file_drag_types_count, GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_ASK); g_signal_connect(G_OBJECT(vdt->treeview), "drag_data_get", G_CALLBACK(vdtree_dnd_get), vdt); g_signal_connect(G_OBJECT(vdt->treeview), "drag_begin", G_CALLBACK(vdtree_dnd_begin), vdt); g_signal_connect(G_OBJECT(vdt->treeview), "drag_end", G_CALLBACK(vdtree_dnd_end), vdt); vdtree_dest_set(vdt, TRUE); g_signal_connect(G_OBJECT(vdt->treeview), "drag_data_received", G_CALLBACK(vdtree_dnd_drop_receive), vdt); g_signal_connect(G_OBJECT(vdt->treeview), "drag_motion", G_CALLBACK(vdtree_dnd_drop_motion), vdt); g_signal_connect(G_OBJECT(vdt->treeview), "drag_leave", G_CALLBACK(vdtree_dnd_drop_leave), vdt);}/* *---------------------------------------------------------------------------- * parts lists *---------------------------------------------------------------------------- */static GList *parts_list(const gchar *path){ GList *list = NULL; const gchar *strb, *strp; gint l; strp = path; if (*strp != '/') return NULL; strp++; strb = strp; l = 0; while (*strp != '\0') { if (*strp == '/') { if (l > 0) list = g_list_prepend(list, g_strndup(strb, l)); strp++; strb = strp; l = 0; } else { strp++; l++; } } if (l > 0) list = g_list_prepend(list, g_strndup(strb, l)); list = g_list_reverse(list); list = g_list_prepend(list, g_strdup("/")); return list;}static void parts_list_free(GList *list){ GList *work = list; while (work) { PathData *pd = work->data; g_free(pd->name); g_free(pd); work = work->next; } g_list_free(list);}static GList *parts_list_add_node_points(ViewDirTree *vdt, GList *list){ GList *work; GtkTreeModel *store; GtkTreeIter iter; gint valid; store = gtk_tree_view_get_model(GTK_TREE_VIEW(vdt->treeview)); valid = gtk_tree_model_get_iter_first(store, &iter); work = list; while (work) { PathData *pd; FileData *fd = NULL; pd = g_new0(PathData, 1); pd->name = work->data; while (valid && !fd) { NodeData *nd; gtk_tree_model_get(store, &iter, DIR_COLUMN_POINTER, &nd, -1); if (strcmp(nd->fd->name, pd->name) == 0) { fd = nd->fd; } else { valid = gtk_tree_model_iter_next(store, &iter); } } pd->node = fd; work->data = pd; if (fd) { GtkTreeIter parent; memcpy(&parent, &iter, sizeof(parent)); valid = gtk_tree_model_iter_children(store, &iter, &parent); } work = work->next; } return list;}/* *---------------------------------------------------------------------------- * misc *---------------------------------------------------------------------------- */#if 0static void vdtree_row_deleted_cb(GtkTreeModel *tree_model, GtkTreePath *tpath, gpointer data){ GtkTreeIter iter; NodeData *nd; gtk_tree_model_get_iter(tree_model, &iter, tpath); gtk_tree_model_get(tree_model, &iter, DIR_COLUMN_POINTER, &nd, -1); if (!nd) return; file_data_free(nd->fd); g_free(nd);}#endif/* *---------------------------------------------------------------------------- * node traversal, management *---------------------------------------------------------------------------- */static gint vdtree_find_iter_by_data(ViewDirTree *vdt, GtkTreeIter *parent, NodeData *nd, GtkTreeIter *iter){ GtkTreeModel *store; store = gtk_tree_view_get_model(GTK_TREE_VIEW(vdt->treeview)); if (!nd || !gtk_tree_model_iter_children(store, iter, parent)) return -1; do { NodeData *cnd; gtk_tree_model_get(store, iter, DIR_COLUMN_POINTER, &cnd, -1); if (cnd == nd) return TRUE; } while (gtk_tree_model_iter_next(store, iter)); return FALSE;}static NodeData *vdtree_find_iter_by_name(ViewDirTree *vdt, GtkTreeIter *parent, const gchar *name, GtkTreeIter *iter){ GtkTreeModel *store; store = gtk_tree_view_get_model(GTK_TREE_VIEW(vdt->treeview)); if (!name || !gtk_tree_model_iter_children(store, iter, parent)) return NULL; do { NodeData *nd; gtk_tree_model_get(store, iter, DIR_COLUMN_POINTER, &nd, -1); if (nd && strcmp(nd->fd->name, name) == 0) return nd; } while (gtk_tree_model_iter_next(store, iter)); return NULL;}static void vdtree_add_by_data(ViewDirTree *vdt, FileData *fd, GtkTreeIter *parent){ GtkTreeStore *store; GtkTreeIter child; GList *list; NodeData *nd; GdkPixbuf *pixbuf; NodeData *end; GtkTreeIter empty; if (!fd) return; list = parts_list(fd->path); if (!list) return; if (access_file(fd->path, R_OK | X_OK)) { pixbuf = vdt->pf->close; } else { pixbuf = vdt->pf->deny; } nd = g_new0(NodeData, 1); nd->fd = fd; nd->expanded = FALSE; nd->last_update = time(NULL); store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vdt->treeview))); gtk_tree_store_append(store, &child, parent); gtk_tree_store_set(store, &child, DIR_COLUMN_POINTER, nd, DIR_COLUMN_ICON, pixbuf, DIR_COLUMN_NAME, nd->fd->name, DIR_COLUMN_COLOR, FALSE, -1); /* all nodes are created with an "empty" node, so that the expander is shown * this is removed when the child is populated */ end = g_new0(NodeData, 1); end->fd = g_new0(FileData, 1); end->fd->path = g_strdup(""); end->fd->name = end->fd->path; end->expanded = TRUE; gtk_tree_store_append(store, &empty, &child); gtk_tree_store_set(store, &empty, DIR_COLUMN_POINTER, end, DIR_COLUMN_NAME, "empty", -1); if (parent) { NodeData *pnd; GtkTreePath *tpath; gtk_tree_model_get(GTK_TREE_MODEL(store), parent, DIR_COLUMN_POINTER, &pnd, -1); tpath = gtk_tree_model_get_path(GTK_TREE_MODEL(store), parent); if (tree_descend_subdirs && gtk_tree_view_row_expanded(GTK_TREE_VIEW(vdt->treeview), tpath) && !nd->expanded) { vdtree_populate_path_by_iter(vdt, &child, FALSE, vdt->path); } gtk_tree_path_free(tpath); }}static gint vdtree_populate_path_by_iter(ViewDirTree *vdt, GtkTreeIter *iter, gint force, const gchar *target_path){ GtkTreeModel *store; GList *list; GList *work; GList *old; time_t current_time; GtkTreeIter child; NodeData *nd; store = gtk_tree_view_get_model(GTK_TREE_VIEW(vdt->treeview)); gtk_tree_model_get(store, iter, DIR_COLUMN_POINTER, &nd, -1); if (!nd) return FALSE; current_time = time(NULL); if (nd->expanded) { if (!force && current_time - nd->last_update < 10) return TRUE; if (!isdir(nd->fd->path)) { if (vdt->click_fd == nd->fd) vdt->click_fd = NULL; if (vdt->drop_fd == nd->fd) vdt->drop_fd = NULL; gtk_tree_store_remove(GTK_TREE_STORE(store), iter); vdtree_node_free(nd); return FALSE; } if (!force && filetime(nd->fd->path) == nd->fd->date) return TRUE; } vdtree_busy_push(vdt); list = NULL; filelist_read(nd->fd->path, NULL, &list); /* when hidden files are not enabled, and the user enters a hidden path, * allow the tree to display that path by specifically inserting the hidden entries */ if (!show_dot_files && target_path && strncmp(nd->fd->path, target_path, strlen(nd->fd->path)) == 0) { gint n; n = strlen(nd->fd->path); if (target_path[n] == '/' && target_path[n+1] == '.') { gchar *name8; gchar *namel; struct stat sbuf; n++; while (target_path[n] != '\0' && target_path[n] != '/') n++; name8 = g_strndup(target_path, n); namel = path_from_utf8(name8); if (stat_utf8(name8, &sbuf)) { list = g_list_prepend(list, file_data_new(namel, &sbuf)); } g_free(namel); g_free(name8); } } old = NULL; if (gtk_tree_model_iter_children(store, &child, iter)) { do { NodeData *cnd; gtk_tree_model_get(store, &child, DIR_COLUMN_POINTER, &cnd, -1); old = g_list_prepend(old, cnd); } while (gtk_tree_model_iter_next(store, &child)); } work = list; while (work) { FileData *fd; fd = work->data; work = work->next; if (strcmp(fd->name, ".") == 0 || strcmp(fd->name, "..") == 0) { file_data_free(fd); } else { NodeData *cnd; cnd = vdtree_find_iter_by_name(vdt, iter, fd->name, &child); if (cnd) { old = g_list_remove(old, cnd); if (cnd->expanded && cnd->fd->date != fd->date && vdtree_populate_path_by_iter(vdt, &child, FALSE, target_path)) { cnd->fd->size = fd->size; cnd->fd->date = fd->date; } file_data_free(fd); } else { vdtree_add_by_data(vdt, fd, iter); } } } work = old; while (work) { NodeData *cnd = work->data; work = work->next; if (vdt->click_fd == cnd->fd) vdt->click_fd = NULL; if (vdt->drop_fd == cnd->fd) vdt->drop_fd = NULL; if (vdtree_find_iter_by_data(vdt, iter, cnd, &child)) { gtk_tree_store_remove(GTK_TREE_STORE(store), &child); vdtree_node_free(cnd); } } g_list_free(old); g_list_free(list); vdtree_busy_pop(vdt); nd->expanded = TRUE; nd->last_update = current_time; return TRUE;}static FileData *vdtree_populate_path(ViewDirTree *vdt, const gchar *path, gint expand, gint force){ GList *list; GList *work; FileData *fd = NULL; if (!path) return NULL; vdtree_busy_push(vdt);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -