📄 collect-table.c
字号:
void collection_table_file_update(CollectTable *ct, CollectInfo *info){ GtkTreeIter iter; gint row, col; gdouble value; if (!info) { collection_table_update_extras(ct, FALSE, 0.0); return; } if (!collection_table_find_position(ct, info, &row, &col)) return; if (ct->columns != 0 && ct->rows != 0) { value = (gdouble)(row * ct->columns + col) / (ct->columns * ct->rows); } else { value = 0.0; } collection_table_update_extras(ct, TRUE, value); if (collection_table_find_iter(ct, info, &iter, NULL)) { GtkTreeModel *store; GList *list; store = gtk_tree_view_get_model(GTK_TREE_VIEW(ct->listview)); gtk_tree_model_get(store, &iter, CTABLE_COLUMN_POINTER, &list, -1); gtk_list_store_set(GTK_LIST_STORE(store), &iter, CTABLE_COLUMN_POINTER, list, -1); }}void collection_table_file_add(CollectTable *ct, CollectInfo *info){ collection_table_sync_idle(ct);}void collection_table_file_insert(CollectTable *ct, CollectInfo *ci){ collection_table_sync_idle(ct);}void collection_table_file_remove(CollectTable *ct, CollectInfo *ci){ if (ci && INFO_SELECTED(ci)) { ct->selection = g_list_remove(ct->selection, ci); } collection_table_sync_idle(ct);}void collection_table_refresh(CollectTable *ct){ collection_table_populate(ct, FALSE);}/* *------------------------------------------------------------------- * dnd *------------------------------------------------------------------- */static void collection_table_add_dir_recursive(CollectTable *ct, gchar *path, gint recursive){ GList *d = NULL; GList *f = NULL; if (path_list(path, &f, recursive ? &d : NULL)) { GList *work; f = path_list_filter(f, FALSE); d = path_list_filter(d, TRUE); f = path_list_sort(f); d = path_list_sort(d); collection_table_insert_path_list(ct, f, ct->marker_info); work = g_list_last(d); while (work) { collection_table_add_dir_recursive(ct, (gchar *)work->data, TRUE); work = work->prev; } path_list_free(f); path_list_free(d); }}static void confirm_dir_list_do(CollectTable *ct, GList *list, gint recursive){ GList *work = list; while (work) { gchar *path = work->data; work = work->next; if (isdir(path)) collection_table_add_dir_recursive(ct, path, recursive); } collection_table_insert_path_list(ct, list, ct->marker_info);}static void confirm_dir_list_add(GtkWidget *widget, gpointer data){ CollectTable *ct = data; confirm_dir_list_do(ct, ct->drop_list, FALSE);}static void confirm_dir_list_recurse(GtkWidget *widget, gpointer data){ CollectTable *ct = data; confirm_dir_list_do(ct, ct->drop_list, TRUE);}static void confirm_dir_list_skip(GtkWidget *widget, gpointer data){ CollectTable *ct = data; collection_table_insert_path_list(ct, ct->drop_list, ct->marker_info);}static GtkWidget *collection_table_drop_menu(CollectTable *ct){ GtkWidget *menu; menu = popup_menu_short_lived(); g_signal_connect(G_OBJECT(menu), "destroy", G_CALLBACK(collection_table_popup_destroy_cb), ct); menu_item_add_stock(menu, _("Dropped list includes folders."), GTK_STOCK_DND_MULTIPLE, NULL, NULL); menu_item_add_divider(menu); menu_item_add_stock(menu, _("_Add contents"), GTK_STOCK_OK, G_CALLBACK(confirm_dir_list_add), ct); menu_item_add_stock(menu, _("Add contents _recursive"), GTK_STOCK_ADD, G_CALLBACK(confirm_dir_list_recurse), ct); menu_item_add_stock(menu, _("_Skip folders"), GTK_STOCK_REMOVE, G_CALLBACK(confirm_dir_list_skip), ct); menu_item_add_divider(menu); menu_item_add_stock(menu, _("Cancel"), GTK_STOCK_CANCEL, NULL, ct); return menu;}/* *------------------------------------------------------------------- * dnd *------------------------------------------------------------------- */static GtkTargetEntry collection_drag_types[] = { { "application/x-gqview-collection-member", 0, TARGET_APP_COLLECTION_MEMBER }, { "text/uri-list", 0, TARGET_URI_LIST }, { "text/plain", 0, TARGET_TEXT_PLAIN }};static gint n_collection_drag_types = 3;static GtkTargetEntry collection_drop_types[] = { { "application/x-gqview-collection-member", 0, TARGET_APP_COLLECTION_MEMBER }, { "text/uri-list", 0, TARGET_URI_LIST }};static gint n_collection_drop_types = 2;static void collection_table_dnd_get(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time, gpointer data){ CollectTable *ct = data; gint selected; GList *list = NULL; gchar *uri_text = NULL; gint total; if (!ct->click_info) return; selected = INFO_SELECTED(ct->click_info); switch (info) { case TARGET_APP_COLLECTION_MEMBER: if (selected) { uri_text = collection_info_list_to_dnd_data(ct->cd, ct->selection, &total); } else { list = g_list_append(NULL, ct->click_info); uri_text = collection_info_list_to_dnd_data(ct->cd, list, &total); g_list_free(list); } break; case TARGET_URI_LIST: case TARGET_TEXT_PLAIN: default: if (selected) { list = collection_table_selection_get_list(ct); } else { const gchar *path = ct->click_info->path; list = g_list_append(NULL, g_strdup(path)); } if (!list) return; uri_text = uri_text_from_list(list, &total, (info == TARGET_TEXT_PLAIN)); path_list_free(list); break; } gtk_selection_data_set(selection_data, selection_data->target, 8, uri_text, total); g_free(uri_text);}static void collection_table_dnd_receive(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time, gpointer data){ CollectTable *ct = data; GList *list = NULL; GList *info_list = NULL; CollectionData *source; CollectInfo *drop_info; GList *work; if (debug) printf(selection_data->data); collection_table_scroll(ct, FALSE); collection_table_insert_marker(ct, NULL, FALSE); drop_info = collection_table_insert_point(ct, x, y); switch (info) { case TARGET_APP_COLLECTION_MEMBER: source = collection_from_dnd_data((gchar *)selection_data->data, &list, &info_list); if (source) { if (source == ct->cd) { gint row = -1; gint col = -1; /* it is a move within a collection */ path_list_free(list); list = NULL; if (!drop_info) { collection_table_move_by_info_list(ct, info_list, -1, -1); } else if (collection_table_find_position(ct, drop_info, &row, &col)) { collection_table_move_by_info_list(ct, info_list, row, col); } } else { /* it is a move/copy across collections */ if (context->action == GDK_ACTION_MOVE) { collection_remove_by_info_list(source, info_list); } } g_list_free(info_list); } break; case TARGET_URI_LIST: list = uri_list_from_text(selection_data->data, TRUE); work = list; while (work) { if (isdir((gchar *)work->data)) { GtkWidget *menu; ct->drop_list = list; ct->drop_info = drop_info; menu = collection_table_drop_menu(ct); gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, time); return; } work = work->next; } break; default: list = NULL; break; } if (list) { collection_table_insert_path_list(ct, list, drop_info); path_list_free(list); }}static void collection_table_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data){ CollectTable *ct = data; if (ct->click_info && ct->click_info->pixbuf) { gint items; if (INFO_SELECTED(ct->click_info)) items = g_list_length(ct->selection); else items = 1; dnd_set_drag_icon(widget, context, ct->click_info->pixbuf, items); }}static void collection_table_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data){ CollectTable *ct = data; /* apparently a leave event is not generated on a drop */ tip_unschedule(ct); collection_table_scroll(ct, FALSE);}static gint collection_table_dnd_motion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, gpointer data){ CollectTable *ct = data; collection_table_motion_update(ct, x, y, TRUE); collection_table_scroll(ct, TRUE); return FALSE;}static void collection_table_dnd_leave(GtkWidget *widget, GdkDragContext *context, guint time, gpointer data){ CollectTable *ct = data; collection_table_scroll(ct, FALSE);} static void collection_table_dnd_init(CollectTable *ct){ gtk_drag_source_set(ct->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, collection_drag_types, n_collection_drag_types, GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK); g_signal_connect(G_OBJECT(ct->listview), "drag_data_get", G_CALLBACK(collection_table_dnd_get), ct); g_signal_connect(G_OBJECT(ct->listview), "drag_begin", G_CALLBACK(collection_table_dnd_begin), ct); g_signal_connect(G_OBJECT(ct->listview), "drag_end", G_CALLBACK(collection_table_dnd_end), ct); gtk_drag_dest_set(ct->listview, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, collection_drop_types, n_collection_drop_types, GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_ASK); g_signal_connect(G_OBJECT(ct->listview), "drag_motion", G_CALLBACK(collection_table_dnd_motion), ct); g_signal_connect(G_OBJECT(ct->listview), "drag_leave", G_CALLBACK(collection_table_dnd_leave), ct); g_signal_connect(G_OBJECT(ct->listview), "drag_data_received", G_CALLBACK(collection_table_dnd_receive), ct);}/* *----------------------------------------------------------------------------- * draw, etc. *----------------------------------------------------------------------------- */typedef struct _ColumnData ColumnData;struct _ColumnData{ CollectTable *ct; gint number;};static void collection_table_cell_data_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data){ ColumnData *cd = data; CollectTable *ct; GtkStyle *style; GList *list; CollectInfo *info; GdkColor color_fg; GdkColor color_bg; ct = cd->ct; gtk_tree_model_get(tree_model, iter, CTABLE_COLUMN_POINTER, &list, -1); info = g_list_nth_data(list, cd->number); style = gtk_widget_get_style(ct->listview); if (info && (info->flag_mask & SELECTION_SELECTED) ) { memcpy(&color_fg, &style->text[GTK_STATE_SELECTED], sizeof(color_fg)); memcpy(&color_bg, &style->base[GTK_STATE_SELECTED], sizeof(color_bg)); } else { memcpy(&color_fg, &style->text[GTK_STATE_NORMAL], sizeof(color_fg)); memcpy(&color_bg, &style->base[GTK_STATE_NORMAL], sizeof(color_bg)); } if (info && (info->flag_mask & SELECTION_PRELIGHT)) {#if 0 shift_color(&color_fg, -1, 0);#endif shift_color(&color_bg, -1, 0); } if (GQV_IS_CELL_RENDERER_ICON(cell)) { if (info) { g_object_set(cell, "pixbuf", info->pixbuf, "text", filename_from_path(info->path), "cell-background-gdk", &color_bg, "cell-background-set", TRUE, "foreground-gdk", &color_fg, "foreground-set", TRUE, "has-focus", (ct->focus_info == info), NULL); } else { g_object_set(cell, "pixbuf", NULL, "text", NULL, "cell-background-set", FALSE, "foreground-set", FALSE, "has-focus", FALSE, NULL); } }}static void collection_table_append_column(CollectTable *ct, gint n){ ColumnData *cd; GtkTreeViewColumn *column; GtkCellRenderer *renderer; column = gtk_tree_view_column_new(); gtk_tree_view_column_set_min_width(column, 0); gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_alignment(column, 0.5); renderer = gqv_cell_renderer_icon_new(); gtk_tree_view_column_pack_start(column, renderer, FALSE); g_object_set(G_OBJECT(renderer), "xpad", THUMB_BORDER_PADDING * 2, "ypad", THUMB_BORDER_PADDING, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL); g_object_set_data(G_OBJECT(column), "column_number", GINT_TO_POINTER(n)); cd = g_new0(ColumnData, 1); cd->ct = ct; cd->number = n; gtk_tree_view_column_set_cell_data_func(column, renderer, collection_table_cell_data_cb, cd, g_free); gtk_tree_view_append_column(GTK_TREE_VIEW(ct->listview), column);}/* *------------------------------------------------------------------- * init, destruction *------------------------------------------------------------------- */static void collection_table_destroy(GtkWidget *widget, gpointer data){ CollectTable *ct = data; if (ct->popup) { g_signal_handlers_disconnect_matched(GTK_OBJECT(ct->popup), G_SIGNAL_MATCH_DATA, 0, 0, 0, NULL, ct); gtk_widget_destroy(ct->popup); } if (ct->sync_idle_id != -1) g_source_remove(ct->sync_idle_id); tip_unschedule(ct); collection_table_scroll(ct, FALSE); g_free(ct);}static void collection_table_sized(GtkWidget *widget, GtkAllocation *allocation, gpointer data){ CollectTable *ct = data; collection_table_populate_at_new_size(ct, allocation->width, allocation->height, FALSE);}CollectTable *collection_table_new(CollectionData *cd){ CollectTable *ct; GtkListStore *store; GtkTreeSelection *selection; gint i; ct = g_new0(CollectTable, 1); ct->cd = cd; ct->columns = 0; ct->rows = 0; ct->selection = NULL; ct->prev_selection = NULL; ct->tip_window = NULL; ct->tip_delay_id = -1; ct->marker_window = NULL; ct->marker_info = NULL; ct->status_label = NULL; ct->extra_label = NULL; ct->focus_row = 0; ct->focus_column = 0; ct->focus_info = NULL; ct->show_text = show_icon_names; ct->sync_idle_id = -1; ct->drop_idle_id = -1; ct->popup = NULL; ct->drop_info = NULL; ct->drop_list = NULL; ct->scrolled = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ct->scrolled), GTK_SHADOW_IN); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (ct->scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); store = gtk_list_store_new(1, G_TYPE_POINTER); ct->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); g_object_unref(store); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ct->listview)); gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_NONE); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(ct->listview), FALSE); gtk_tree_view_set_enable_search(GTK_TREE_VIEW(ct->listview), FALSE); for (i = 0; i < COLLECT_TABLE_MAX_COLUMNS; i++) { collection_table_append_column(ct, i); } /* zero width column to hide tree view focus, we draw it ourselves */ collection_table_append_column(ct, i); /* end column to fill white space */ collection_table_append_column(ct, i); g_signal_connect(G_OBJECT(ct->listview), "destroy", G_CALLBACK(collection_table_destroy), ct); g_signal_connect(G_OBJECT(ct->listview), "size_allocate", G_CALLBACK(collection_table_sized), ct); g_signal_connect(G_OBJECT(ct->listview), "key_press_event", G_CALLBACK(collection_table_press_key_cb), ct); gtk_container_add(GTK_CONTAINER(ct->scrolled), ct->listview); gtk_widget_show(ct->listview); collection_table_dnd_init(ct); gtk_widget_set_events(ct->listview, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_LEAVE_NOTIFY_MASK); g_signal_connect(G_OBJECT(ct->listview),"button_press_event", G_CALLBACK(collection_table_press_cb), ct); g_signal_connect(G_OBJECT(ct->listview),"button_release_event", G_CALLBACK(collection_table_release_cb), ct); g_signal_connect(G_OBJECT(ct->listview),"motion_notify_event", G_CALLBACK(collection_table_motion_cb), ct); g_signal_connect(G_OBJECT(ct->listview), "leave_notify_event", G_CALLBACK(collection_table_leave_cb), ct); return ct;}void collection_table_set_labels(CollectTable *ct, GtkWidget *status, GtkWidget *extra){ ct->status_label = status; ct->extra_label = extra; collection_table_update_status(ct); collection_table_update_extras(ct, FALSE, 0.0);}CollectInfo *collection_table_get_focus_info(CollectTable *ct){ return collection_table_find_data(ct, ct->focus_row, ct->focus_column, NULL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -