📄 dupe.c
字号:
store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(dw->listview))); gtk_list_store_clear(store); work = g_list_last(dw->dupes); while (work) { DupeItem *parent = work->data; GList *temp; dupe_listview_add(dw, parent, NULL); temp = g_list_last(parent->group); while (temp) { DupeMatch *dm = temp->data; DupeItem *child; child = dm->di; dupe_listview_add(dw, parent, child); temp = temp->prev; } work = work->prev; } gtk_tree_view_columns_autosize(GTK_TREE_VIEW(dw->listview));}static void dupe_listview_remove(DupeWindow *dw, DupeItem *di){ GtkListStore *store; GtkTreeIter iter; gint row; if (!di) return; store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(dw->listview))); row = dupe_listview_find_item(store, di, &iter); if (row < 0) return; tree_view_move_cursor_away(GTK_TREE_VIEW(dw->listview), &iter, TRUE); gtk_list_store_remove(store, &iter); if (g_list_find(dw->dupes, di) != NULL) { if (!dw->color_frozen) dupe_listview_realign_colors(dw); }}static GList *dupe_listview_get_path_list(DupeWindow *dw, GtkWidget *listview){ GtkTreeModel *store; GtkTreeIter iter; gint valid; GList *list = NULL; store = gtk_tree_view_get_model(GTK_TREE_VIEW(listview)); valid = gtk_tree_model_get_iter_first(store, &iter); while (valid) { DupeItem *di; gtk_tree_model_get(store, &iter, DUPE_COLUMN_POINTER, &di, -1); list = g_list_prepend(list, g_strdup(di->path)); valid = gtk_tree_model_iter_next(store, &iter); } return g_list_reverse(list);}static GList *dupe_listview_get_selection(DupeWindow *dw, GtkWidget *listview){ GtkTreeModel *store; GtkTreeSelection *selection; GList *slist; GList *list = NULL; GList *work; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(listview)); slist = gtk_tree_selection_get_selected_rows(selection, &store); work = slist; while (work) { GtkTreePath *tpath = work->data; DupeItem *di = NULL; GtkTreeIter iter; gtk_tree_model_get_iter(store, &iter, tpath); gtk_tree_model_get(store, &iter, DUPE_COLUMN_POINTER, &di, -1); if (di) { list = g_list_prepend(list, g_strdup(di->path)); } work = work->next; } g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL); g_list_free(slist); return g_list_reverse(list);}static gint dupe_listview_item_is_selected(DupeWindow *dw, DupeItem *di, GtkWidget *listview){ GtkTreeModel *store; GtkTreeSelection *selection; GList *slist; GList *work; gint found = FALSE; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(listview)); slist = gtk_tree_selection_get_selected_rows(selection, &store); work = slist; while (!found && work) { GtkTreePath *tpath = work->data; DupeItem *di_n; GtkTreeIter iter; gtk_tree_model_get_iter(store, &iter, tpath); gtk_tree_model_get(store, &iter, DUPE_COLUMN_POINTER, &di_n, -1); if (di_n == di) found = TRUE; work = work->next; } g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL); g_list_free(slist); return found;}static void dupe_listview_select_dupes(DupeWindow *dw, gint parents){ GtkTreeModel *store; GtkTreeSelection *selection; GtkTreeIter iter; gint valid; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dw->listview)); gtk_tree_selection_unselect_all(selection); store = gtk_tree_view_get_model(GTK_TREE_VIEW(dw->listview)); valid = gtk_tree_model_get_iter_first(store, &iter); while (valid) { DupeItem *di; gtk_tree_model_get(store, &iter, DUPE_COLUMN_POINTER, &di, -1); if ( (dupe_match_find_parent(dw, di) == di) == (parents) ) { gtk_tree_selection_select_iter(selection, &iter); } valid = gtk_tree_model_iter_next(store, &iter); }}/* * ------------------------------------------------------------------ * Match group manipulation * ------------------------------------------------------------------ */static DupeMatch *dupe_match_find_match(DupeItem *child, DupeItem *parent){ GList *work; work = parent->group; while (work) { DupeMatch *dm = work->data; if (dm->di == child) return dm; work = work->next; } return NULL;}static void dupe_match_link_child(DupeItem *child, DupeItem *parent, gdouble rank){ DupeMatch *dm; dm = g_new0(DupeMatch, 1); dm->di = child; dm->rank = rank; parent->group = g_list_append(parent->group, dm);}static void dupe_match_link(DupeItem *a, DupeItem *b, gdouble rank){ dupe_match_link_child(a, b, rank); dupe_match_link_child(b, a, rank);}static void dupe_match_unlink_child(DupeItem *child, DupeItem *parent){ DupeMatch *dm; dm = dupe_match_find_match(child, parent); if (dm) { parent->group = g_list_remove(parent->group, dm); g_free(dm); }}static void dupe_match_unlink(DupeItem *a, DupeItem *b){ dupe_match_unlink_child(a, b); dupe_match_unlink_child(b, a);}static void dupe_match_link_clear(DupeItem *parent, gint unlink_children){ GList *work; work = parent->group; while (work) { DupeMatch *dm = work->data; work = work->next; if (unlink_children) dupe_match_unlink_child(parent, dm->di); g_free(dm); } g_list_free(parent->group); parent->group = NULL; parent->group_rank = 0.0;}static gint dupe_match_link_exists(DupeItem *child, DupeItem *parent){ return (dupe_match_find_match(child, parent) != NULL);}static gdouble dupe_match_link_rank(DupeItem *child, DupeItem *parent){ DupeMatch *dm; dm = dupe_match_find_match(child, parent); if (dm) return dm->rank; return 0.0;}static DupeItem *dupe_match_highest_rank(DupeItem *child){ DupeMatch *dr; GList *work; dr = NULL; work = child->group; while (work) { DupeMatch *dm = work->data; if (!dr || dm->rank > dr->rank) dr = dm; work = work->next; } return (dr) ? dr->di : NULL;}static void dupe_match_rank_update(DupeItem *parent){ GList *work; gdouble rank = 0.0; gint c = 0; work = parent->group; while (work) { DupeMatch *dm = work->data; work = work->next; rank += dm->rank; c++; } if (c > 0) { parent->group_rank = rank / c; } else { parent->group_rank = 0.0; }}static DupeItem *dupe_match_find_parent(DupeWindow *dw, DupeItem *child){ GList *work; if (g_list_find(dw->dupes, child)) return child; work = child->group; while (work) { DupeMatch *dm = work->data; if (g_list_find(dw->dupes, dm->di)) return dm->di; work = work->next; } return NULL;}static void dupe_match_reset_list(GList *work){ while (work) { DupeItem *di = work->data; work = work->next; dupe_match_link_clear(di, FALSE); }}static void dupe_match_reparent(DupeWindow *dw, DupeItem *old, DupeItem *new){ GList *work; if (!old || !new || !dupe_match_link_exists(old, new)) return; dupe_match_link_clear(new, TRUE); work = old->group; while (work) { DupeMatch *dm = work->data; dupe_match_unlink_child(old, dm->di); dupe_match_link_child(new, dm->di, dm->rank); work = work->next; } new->group = old->group; old->group = NULL; work = g_list_find(dw->dupes, old); if (work) work->data = new;}static void dupe_match_print_group(DupeItem *di){ GList *work; printf("+ %f %s\n", di->group_rank, di->name); work = di->group; while (work) { DupeMatch *dm = work->data; work = work->next; printf(" %f %s\n", dm->rank, dm->di->name); } printf("\n");}static void dupe_match_print_list(GList *list){ GList *work; work = list; while (work) { DupeItem *di = work->data; dupe_match_print_group(di); work = work->next; }}/* level 3, unlinking and orphan handling */static GList *dupe_match_unlink_by_rank(DupeItem *child, DupeItem *parent, GList *list, DupeWindow *dw){ DupeItem *best; best = dupe_match_highest_rank(parent); if (best == child || dupe_match_highest_rank(child) == parent) { GList *work; gdouble rank; if (debug > 1) printf("link found %s to %s [%d]\n", child->name, parent->name, g_list_length(parent->group)); work = parent->group; while (work) { DupeMatch *dm = work->data; DupeItem *orphan; work = work->next; orphan = dm->di; if (orphan != child && g_list_length(orphan->group) < 2) { dupe_match_link_clear(orphan, TRUE); if (!dw->second_set || orphan->second) { dupe_match(orphan, child, dw->match_mask, &rank, FALSE); dupe_match_link(orphan, child, rank); } list = g_list_remove(list, orphan); } } rank = dupe_match_link_rank(child, parent); dupe_match_link_clear(parent, TRUE); dupe_match_link(child, parent, rank); list = g_list_remove(list, parent); } else { if (debug > 1) printf("unlinking %s and %s\n", child->name, parent->name); dupe_match_unlink(child, parent); } return list;}/* level 2 */static GList *dupe_match_group_filter(GList *list, DupeItem *di, DupeWindow *dw){ GList *work; work = g_list_last(di->group); while (work) { DupeMatch *dm = work->data; work = work->prev; list = dupe_match_unlink_by_rank(di, dm->di, list, dw); } return list;}/* level 1 (top) */static GList *dupe_match_group_trim(GList *list, DupeWindow *dw){ GList *work; work = list; while (work) { DupeItem *di = work->data; if (!di->second) list = dupe_match_group_filter(list, di, dw); work = work->next; if (di->second) list = g_list_remove(list, di); } return list;}static gint dupe_match_sort_groups_cb(gconstpointer a, gconstpointer b){ DupeMatch *da = (DupeMatch *)a; DupeMatch *db = (DupeMatch *)b; if (da->rank > db->rank) return -1; if (da->rank < db->rank) return 1; return 0;}static void dupe_match_sort_groups(GList *list){ GList *work; work = list; while (work) { DupeItem *di = work->data; di->group = g_list_sort(di->group, dupe_match_sort_groups_cb); work = work->next; }}static gint dupe_match_rank_sort_cb(gconstpointer a, gconstpointer b){ DupeItem *da = (DupeItem *)a; DupeItem *db = (DupeItem *)b; if (da->group_rank > db->group_rank) return -1; if (da->group_rank < db->group_rank) return 1; return 0;}/* returns allocated GList of dupes sorted by rank */static GList *dupe_match_rank_sort(GList *source_list){ GList *list = NULL; GList *work; work = source_list; while (work) { DupeItem *di = work->data; if (di->group) { dupe_match_rank_update(di); list = g_list_prepend(list, di); } work = work->next; } return g_list_sort(list, dupe_match_rank_sort_cb);}static void dupe_match_rank(DupeWindow *dw){ GList *list; list = dupe_match_rank_sort(dw->list); if (debug > 1) dupe_match_print_list(list); if (debug) printf("Similar items: %d\n", g_list_length(list)); list = dupe_match_group_trim(list, dw); if (debug) printf("Unique groups: %d\n", g_list_length(list)); dupe_match_sort_groups(list); if (debug) dupe_match_print_list(list); list = dupe_match_rank_sort(list); g_list_free(dw->dupes); dw->dupes = list;}/* * ------------------------------------------------------------------ * Match group tests * ------------------------------------------------------------------ */static gint dupe_match(DupeItem *a, DupeItem *b, DupeMatchType mask, gdouble *rank, gint fast){ *rank = 0.0; if (a == b) return FALSE; if (mask & DUPE_MATCH_PATH) { if (strcmp(a->path, b->path) != 0) return FALSE; } if (mask & DUPE_MATCH_NAME) { if (strcmp(a->name, b->name) != 0) return FALSE; } if (mask & DUPE_MATCH_SIZE) { if (a->size != b->size) return FALSE; } if (mask & DUPE_MATCH_DATE) { if (a->date != b->date) return FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -