📄 dupe.c
字号:
GtkTreeModel *store; GtkTreePath *tpath; GtkTreeIter iter; DupeItem *di = NULL; store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y, &tpath, NULL, NULL, NULL)) { gtk_tree_model_get_iter(store, &iter, tpath); gtk_tree_model_get(store, &iter, DUPE_COLUMN_POINTER, &di, -1); gtk_tree_path_free(tpath); } dw->click_item = di; if (bevent->button == 3) { /* right click menu */ GtkWidget *menu; if (bevent->state & GDK_CONTROL_MASK && bevent->state & GDK_SHIFT_MASK) { dupe_display_stats(dw, di); return TRUE; } if (widget == dw->listview) { menu = dupe_menu_popup_main(dw, di); } else { menu = dupe_menu_popup_second(dw, di); } gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, bevent->button, bevent->time); } if (!di) return FALSE; if (bevent->button == 1 && bevent->type == GDK_2BUTTON_PRESS) { dupe_menu_view(dw, di, widget, FALSE); } if (bevent->button == 2) return TRUE; if (bevent->button == 3) { if (!dupe_listview_item_is_selected(dw, di, widget)) { GtkTreeSelection *selection; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); gtk_tree_selection_unselect_all(selection); gtk_tree_selection_select_iter(selection, &iter); tpath = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter); gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE); gtk_tree_path_free(tpath); } return TRUE; } if (bevent->button == 1 && bevent->type == GDK_BUTTON_PRESS && !(bevent->state & GDK_SHIFT_MASK ) && !(bevent->state & GDK_CONTROL_MASK ) && dupe_listview_item_is_selected(dw, di, widget)) { /* this selection handled on release_cb */ gtk_widget_grab_focus(widget); return TRUE; } return FALSE;}static gint dupe_listview_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data){ DupeWindow *dw = data; GtkTreeModel *store; GtkTreePath *tpath; GtkTreeIter iter; DupeItem *di = NULL; if (bevent->button != 1 && bevent->button != 2) return TRUE; store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); if ((bevent->x != 0 || bevent->y != 0) && gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y, &tpath, NULL, NULL, NULL)) { gtk_tree_model_get_iter(store, &iter, tpath); gtk_tree_model_get(store, &iter, DUPE_COLUMN_POINTER, &di, -1); gtk_tree_path_free(tpath); } if (bevent->button == 2) { if (di && dw->click_item == di) { GtkTreeSelection *selection; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); if (dupe_listview_item_is_selected(dw, di, widget)) { gtk_tree_selection_unselect_iter(selection, &iter); } else { gtk_tree_selection_select_iter(selection, &iter); } } return TRUE; } if (di && dw->click_item == di && !(bevent->state & GDK_SHIFT_MASK ) && !(bevent->state & GDK_CONTROL_MASK ) && dupe_listview_item_is_selected(dw, di, widget)) { GtkTreeSelection *selection; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); gtk_tree_selection_unselect_all(selection); gtk_tree_selection_select_iter(selection, &iter); tpath = gtk_tree_model_get_path(store, &iter); gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE); gtk_tree_path_free(tpath); return TRUE; } return FALSE;}/* *------------------------------------------------------------------- * second set stuff *------------------------------------------------------------------- */static void dupe_second_update_status(DupeWindow *dw){ gchar *buf; buf = g_strdup_printf(_("%d files (set 2)"), g_list_length(dw->second_list)); gtk_label_set_text(GTK_LABEL(dw->second_status_label), buf); g_free(buf);}static void dupe_second_add(DupeWindow *dw, DupeItem *di){ GtkListStore *store; GtkTreeIter iter; if (!di) return; di->second = TRUE; dw->second_list = g_list_prepend(dw->second_list, di); store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(dw->second_listview))); gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, DUPE_COLUMN_POINTER, di, 1, di->path, -1); dupe_second_update_status(dw);}static void dupe_second_remove(DupeWindow *dw, DupeItem *di){ GtkListStore *store; GtkTreeIter iter; store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(dw->second_listview))); if (dupe_listview_find_item(store, di, &iter) >= 0) { tree_view_move_cursor_away(GTK_TREE_VIEW(dw->second_listview), &iter, TRUE); gtk_list_store_remove(store, &iter); } dw->second_list = g_list_remove(dw->second_list, di); dupe_second_update_status(dw);}static void dupe_second_clear(DupeWindow *dw){ GtkListStore *store; store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(dw->second_listview))); gtk_list_store_clear(store); gtk_tree_view_columns_autosize(GTK_TREE_VIEW(dw->second_listview)); g_list_free(dw->dupes); dw->dupes = NULL; dupe_list_free(dw->second_list); dw->second_list = NULL; dupe_match_reset_list(dw->list); dupe_second_update_status(dw);}static void dupe_second_menu_view_cb(GtkWidget *widget, gpointer data){ DupeWindow *dw = data; if (dw->click_item) dupe_menu_view(dw, dw->click_item, dw->second_listview, FALSE);}static void dupe_second_menu_viewnew_cb(GtkWidget *widget, gpointer data){ DupeWindow *dw = data; if (dw->click_item) dupe_menu_view(dw, dw->click_item, dw->second_listview, TRUE);}static void dupe_second_menu_select_all_cb(GtkWidget *widget, gpointer data){ GtkTreeSelection *selection; DupeWindow *dw = data; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dw->second_listview)); gtk_tree_selection_select_all(selection);}static void dupe_second_menu_select_none_cb(GtkWidget *widget, gpointer data){ GtkTreeSelection *selection; DupeWindow *dw = data; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dw->second_listview)); gtk_tree_selection_unselect_all(selection);}static void dupe_second_menu_remove_cb(GtkWidget *widget, gpointer data){ DupeWindow *dw = data; dupe_window_remove_selection(dw, dw->second_listview);}static void dupe_second_menu_clear_cb(GtkWidget *widget, gpointer data){ DupeWindow *dw = data; dupe_second_clear(dw); dupe_window_recompare(dw);}static GtkWidget *dupe_menu_popup_second(DupeWindow *dw, DupeItem *di){ GtkWidget *menu; gint notempty; gint on_row; on_row = (di != NULL); notempty = (dw->second_list != NULL); menu = popup_menu_short_lived(); menu_item_add_sensitive(menu, _("_View"), on_row, G_CALLBACK(dupe_second_menu_view_cb), dw); menu_item_add_stock_sensitive(menu, _("View in _new window"), GTK_STOCK_NEW, on_row, G_CALLBACK(dupe_second_menu_viewnew_cb), dw); menu_item_add_divider(menu); menu_item_add_sensitive(menu, _("Select all"), notempty, G_CALLBACK(dupe_second_menu_select_all_cb), dw); menu_item_add_sensitive(menu, _("Select none"), notempty, G_CALLBACK(dupe_second_menu_select_none_cb), dw); menu_item_add_divider(menu); menu_item_add_stock_sensitive(menu, _("Rem_ove"), GTK_STOCK_REMOVE, on_row, G_CALLBACK(dupe_second_menu_remove_cb), dw); menu_item_add_stock_sensitive(menu, _("C_lear"), GTK_STOCK_CLEAR, notempty, G_CALLBACK(dupe_second_menu_clear_cb), dw); menu_item_add_divider(menu); menu_item_add_stock(menu, _("Close _window"), GTK_STOCK_CLOSE, G_CALLBACK(dupe_menu_close_cb), dw); return menu;}static void dupe_second_set_toggle_cb(GtkWidget *widget, gpointer data){ DupeWindow *dw = data; dw->second_set = GTK_TOGGLE_BUTTON(widget)->active; if (dw->second_set) { dupe_second_update_status(dw); gtk_table_set_col_spacings(GTK_TABLE(dw->table), PREF_PAD_GAP); gtk_widget_show(dw->second_vbox); } else { gtk_table_set_col_spacings(GTK_TABLE(dw->table), 0); gtk_widget_hide(dw->second_vbox); dupe_second_clear(dw); } dupe_window_recompare(dw);}/* *------------------------------------------------------------------- * match type menu *------------------------------------------------------------------- */enum { DUPE_MENU_COLUMN_NAME = 0, DUPE_MENU_COLUMN_MASK};static void dupe_menu_type_cb(GtkWidget *combo, gpointer data){ DupeWindow *dw = data; GtkTreeModel *store; GtkTreeIter iter; store = gtk_combo_box_get_model(GTK_COMBO_BOX(combo)); if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter)) return; gtk_tree_model_get(store, &iter, DUPE_MENU_COLUMN_MASK, &dw->match_mask, -1); dupe_window_recompare(dw);}static void dupe_menu_add_item(GtkListStore *store, const gchar *text, DupeMatchType type, DupeWindow *dw){ GtkTreeIter iter; gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, DUPE_MENU_COLUMN_NAME, text, DUPE_MENU_COLUMN_MASK, type, -1); if (dw->match_mask == type) gtk_combo_box_set_active_iter(GTK_COMBO_BOX(dw->combo), &iter);}static void dupe_menu_setup(DupeWindow *dw){ GtkListStore *store; GtkCellRenderer *renderer; store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT); dw->combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store)); g_object_unref(store); renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(dw->combo), renderer, TRUE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(dw->combo), renderer, "text", DUPE_MENU_COLUMN_NAME, NULL); dupe_menu_add_item(store, _("Name"), DUPE_MATCH_NAME, dw); dupe_menu_add_item(store, _("Size"), DUPE_MATCH_SIZE, dw); dupe_menu_add_item(store, _("Date"), DUPE_MATCH_DATE, dw); dupe_menu_add_item(store, _("Dimensions"), DUPE_MATCH_DIM, dw); dupe_menu_add_item(store, _("Checksum"), DUPE_MATCH_SUM, dw); dupe_menu_add_item(store, _("Path"), DUPE_MATCH_PATH, dw); dupe_menu_add_item(store, _("Similarity (high)"), DUPE_MATCH_SIM_HIGH, dw); dupe_menu_add_item(store, _("Similarity"), DUPE_MATCH_SIM_MED, dw); dupe_menu_add_item(store, _("Similarity (low)"), DUPE_MATCH_SIM_LOW, dw); dupe_menu_add_item(store, _("Similarity (custom)"), DUPE_MATCH_SIM_CUSTOM, dw); g_signal_connect(G_OBJECT(dw->combo), "changed", G_CALLBACK(dupe_menu_type_cb), dw);}/* *------------------------------------------------------------------- * list view columns *------------------------------------------------------------------- *//* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */#define CELL_HEIGHT_OVERRIDE 512 void cell_renderer_height_override(GtkCellRenderer *renderer){ GParamSpec *spec; spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height"); if (spec && G_IS_PARAM_SPEC_INT(spec)) { GParamSpecInt *spec_int; spec_int = G_PARAM_SPEC_INT(spec); if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE; }}static GdkColor *dupe_listview_color_shifted(GtkWidget *widget){ static GdkColor color; static GtkWidget *done = NULL; if (done != widget) { GtkStyle *style; style = gtk_widget_get_style(widget); memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color)); shift_color(&color, -1, 0); done = widget; } return &color;}static void dupe_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data){ DupeWindow *dw = data; gboolean set; gtk_tree_model_get(tree_model, iter, DUPE_COLUMN_COLOR, &set, -1); g_object_set(G_OBJECT(cell), "cell-background-gdk", dupe_listview_color_shifted(dw->listview), "cell-background-set", set, NULL);}static void dupe_listview_add_column(DupeWindow *dw, GtkWidget *listview, gint n, const gchar *title, gint image, gint right_justify){ GtkTreeViewColumn *column; GtkCellRenderer *renderer; column = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(column, title); gtk_tree_view_column_set_min_width(column, 4); if (n != DUPE_COLUMN_RANK && n != DUPE_COLUMN_THUMB) { gtk_tree_view_column_set_resizable(column, TRUE); } if (!image) { gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY); renderer = gtk_cell_renderer_text_new(); if (right_justify) { g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL); } gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_add_attribute(column, renderer, "text", n); } else { gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); renderer = gtk_cell_renderer_pixbuf_new(); cell_renderer_height_override(renderer); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n); } if (listview == dw->listview) { /* sets background before rendering */ gtk_tree_view_column_set_cell_data_func(column, renderer, dupe_listview_color_cb, dw, NULL); } gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);}static void dupe_listview_set_height(GtkWidget *listview, gint thumb){ GtkTreeViewColumn *column; GtkCellRenderer *cell; GList *list; column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), DUPE_COLUMN_THUMB - 1); if (!column) return; gtk_tree_view_column_set_fixed_width(column, (thumb) ? thumb_max_width : 4); list = gtk_tree_view_column_get_cell_renderers(column); if (!list) return; cell = list->data; g_list_free(list); g_object_set(G_OBJECT(cell), "height", (thumb) ? thumb_max_height : -1, NULL); gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));}/* *------------------------------------------------------------------- * misc cb *------------------------------------------------------------------- */static void dupe_window_show_thumb_cb(GtkWidget *widget, gpointer data){ DupeWindow *dw = data; dw->show_thumbs = GTK_TOGGLE_BUTTON(widget)->active; if (dw->show_thumbs) { if (!dw->working) dupe_thumb_step(dw); } else { GtkTreeModel *store; GtkTreeIter iter; gint valid; thumb_loader_free(dw->thumb_loader); dw->thumb_loader = NULL; store = gtk_tree_view_get_model(GTK_TREE_VIEW(dw->listview)); valid = gtk_tree_model_get_iter_first(store, &iter); while (valid) { gtk_list_store_set(GTK_LIST_STORE(store), &iter, DUPE_COLUMN_THUMB, NULL, -1); valid = gtk_tree_model_iter_next(store, &iter); } dupe_window_update_progress(dw, NULL, 0.0, FALSE); } dupe_listview_set_height(dw->listview, dw->show_thumbs);}static void dupe_popup_menu_pos_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data){ GtkWidget *view = data; GtkTreePath *tpath; gint cx, cy, cw, ch; gint column; gtk_tree_view_get_cursor(GTK_TREE_VIEW(view), &tpath, NULL); if (!tpath) return; if (gtk_tree_view_get_column(GTK_TREE_VIEW(view), DUPE_COLUMN_NAME - 1) != NULL) { column = DUPE_COLUMN_NAME - 1; } else { /* dw->second_listview */ column = 0; } tree_view_get_cell_clamped(GTK_TREE_VIEW(view), tpath, column, TRUE, &cx, &cy, &cw, &ch); gtk_tree_path_free(tpath); cy += ch; popup_menu_position_clamp(menu, &cx, &cy, 0); *x = cx; *y = cy;}static gint dupe_window_keypress_cb(GtkWidget *widget
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -