⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dupe.c

📁 Gqview,Linux下基于GTK+库写成的轻量级而能丰富的图像浏览程序。
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * GQview * (C) 2005 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 "dupe.h"#include "cache.h"#include "collect.h"#include "collect-table.h"#include "dnd.h"#include "editors.h"#include "filelist.h"#include "image-load.h"#include "img-view.h"#include "info.h"#include "layout.h"#include "layout_image.h"#include "md5-util.h"#include "menu.h"#include "print.h"#include "thumb.h"#include "utilops.h"#include "ui_bookmark.h"#include "ui_fileops.h"#include "ui_menu.h"#include "ui_misc.h"#include "ui_tree_edit.h"#include <gdk/gdkkeysyms.h> /* for keyboard values */#include <math.h>#define DUPE_DEF_WIDTH 600#define DUPE_DEF_HEIGHT 400/* column assignment order (simply change them here) */enum {	DUPE_COLUMN_POINTER = 0,	DUPE_COLUMN_RANK,	DUPE_COLUMN_THUMB,	DUPE_COLUMN_NAME,	DUPE_COLUMN_SIZE,	DUPE_COLUMN_DATE,	DUPE_COLUMN_DIMENSIONS,	DUPE_COLUMN_PATH,	DUPE_COLUMN_COLOR,	DUPE_COLUMN_COUNT	/* total columns */};static GList *dupe_window_list = NULL;	/* list of open DupeWindow *s *//* * Well, after adding the 'compare two sets' option things got a little sloppy in here * because we have to account for two 'modes' everywhere. (be careful). */static void dupe_match_unlink(DupeItem *a, DupeItem *b);static DupeItem *dupe_match_find_parent(DupeWindow *dw, DupeItem *child);static gint dupe_match(DupeItem *a, DupeItem *b, DupeMatchType mask, gdouble *rank, gint fast);static void dupe_thumb_step(DupeWindow *dw);static gint dupe_check_cb(gpointer data);static void dupe_second_add(DupeWindow *dw, DupeItem *di);static void dupe_second_remove(DupeWindow *dw, DupeItem *di);static GtkWidget *dupe_menu_popup_second(DupeWindow *dw, DupeItem *di);static void dupe_dnd_init(DupeWindow *dw);/* * ------------------------------------------------------------------ * Window updates * ------------------------------------------------------------------ */static void dupe_window_update_count(DupeWindow *dw, gint count_only){	gchar *text;	if (!dw->list)		{		text = g_strdup(_("Drop files to compare them."));		}	else if (count_only)		{		text = g_strdup_printf(_("%d files"), g_list_length(dw->list));		}	else		{		text = g_strdup_printf(_("%d matches found in %d files"), g_list_length(dw->dupes), g_list_length(dw->list));		}	if (dw->second_set)		{		gchar *buf = g_strconcat(text, " ", _("[set 1]"), NULL);		g_free(text);		text = buf;		}	gtk_label_set_text(GTK_LABEL(dw->status_label), text);	g_free(text);}static guint64 msec_time(void){	struct timeval tv;	if (gettimeofday(&tv, NULL) == -1) return 0;	return (guint64)tv.tv_sec * 1000000 + (guint64)tv.tv_usec;}static gint dupe_iterations(gint n){	return (n * ((n + 1) / 2));}static void dupe_window_update_progress(DupeWindow *dw, const gchar *status, gdouble value, gint force){	const gchar *status_text;	if (status)		{		guint64 new_time = 0;		if (dw->setup_n % 10 == 0)			{			new_time = msec_time() - dw->setup_time;			}				if (!force &&		    value != 0.0 &&		    dw->setup_count > 0 &&		    new_time > 2000000)			{			gchar *buf;			gint t;			gint d;			guint32 rem;			if (new_time - dw->setup_time_count < 250000) return;			dw->setup_time_count = new_time;			if (dw->setup_done)				{				if (dw->second_set)					{					t = dw->setup_count;					d = dw->setup_count - dw->setup_n;					}				else					{					t = dupe_iterations(dw->setup_count);					d = dupe_iterations(dw->setup_count - dw->setup_n);					}				}			else				{				t = dw->setup_count;				d = dw->setup_count - dw->setup_n;				}			rem = (t - d) ? ((gdouble)(dw->setup_time_count / 1000000) / (t - d)) * d : 0;			gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(dw->extra_label), value);			buf = g_strdup_printf("%s %d:%02d ", status, rem / 60, rem % 60);			gtk_progress_bar_set_text(GTK_PROGRESS_BAR(dw->extra_label), buf);			g_free(buf);			return;			}		else if (force ||			 value == 0.0 ||			 dw->setup_count == 0 ||			 dw->setup_time_count == 0 ||			 (new_time > 0 && new_time - dw->setup_time_count >= 250000))			{			if (dw->setup_time_count == 0) dw->setup_time_count = 1;			if (new_time > 0) dw->setup_time_count = new_time;			gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(dw->extra_label), value);			status_text = status;			}		else			{			status_text = NULL;			}		}		else		{		gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(dw->extra_label), 0.0);		status_text = " ";		}	if (status_text) gtk_progress_bar_set_text(GTK_PROGRESS_BAR(dw->extra_label), status_text);}static void widget_set_cursor(GtkWidget *widget, gint icon){	GdkCursor *cursor;	if (!widget->window) return; 	if (icon == -1)		{		cursor = NULL;		}	else		{		cursor = gdk_cursor_new (icon);		} 	gdk_window_set_cursor(widget->window, cursor); 	if (cursor) gdk_cursor_unref(cursor);}/* * ------------------------------------------------------------------ * row color utils * ------------------------------------------------------------------ */static void dupe_listview_realign_colors(DupeWindow *dw){	GtkTreeModel *store;	GtkTreeIter iter;	gboolean color_set = TRUE;	DupeItem *parent = NULL;	gint valid;	store = gtk_tree_view_get_model(GTK_TREE_VIEW(dw->listview));	valid = gtk_tree_model_get_iter_first(store, &iter);	while (valid)		{		DupeItem *child;		DupeItem *child_parent;		gtk_tree_model_get(store, &iter, DUPE_COLUMN_POINTER, &child, -1);		child_parent = dupe_match_find_parent(dw, child);		if (!parent || parent != child_parent)			{			if (!parent)				{				/* keep the first row as it is */				gtk_tree_model_get(store, &iter, DUPE_COLUMN_COLOR, &color_set, -1);				}			else				{				color_set = !color_set;				}			parent = dupe_match_find_parent(dw, child);			}		gtk_list_store_set(GTK_LIST_STORE(store), &iter, DUPE_COLUMN_COLOR, color_set, -1);		valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);		}}/* * ------------------------------------------------------------------ * Dupe item utils * ------------------------------------------------------------------ */static DupeItem *dupe_item_new(const gchar *path, gint64 size, time_t date){	DupeItem *di;	di = g_new0(DupeItem, 1);	di->path = g_strdup(path);	di->name = filename_from_path(di->path);	di->size = size;	di->date = date;	di->group = NULL;	di->group_rank = 0.0;	di->simd = NULL;	di->checksum = 0;	di->md5sum = NULL;	di->width = 0;	di->height = 0;	di->second = FALSE;	return di;}static void dupe_item_free(DupeItem *di){	g_free(di->path);	image_sim_free(di->simd);	g_free(di->md5sum);	if (di->pixbuf) g_object_unref(di->pixbuf);	g_free(di);}static void dupe_list_free(GList *list){	GList *work = list;	while (work)		{		DupeItem *di = work->data;		work = work->next;		dupe_item_free(di);		}	g_list_free(list);}static DupeItem *dupe_item_find_path_by_list(const gchar *path, GList *work){	while (work)		{		DupeItem *di = work->data;		if (strcmp(di->path, path) == 0) return di;		work = work->next;		}	return NULL;}static DupeItem *dupe_item_find_path(DupeWindow *dw, const gchar *path){	DupeItem *di;	di = dupe_item_find_path_by_list(path, dw->list);	if (!di && dw->second_set) di = dupe_item_find_path_by_list(path, dw->second_list);	return di;}/* * ------------------------------------------------------------------ * Image property cache * ------------------------------------------------------------------ */static void dupe_item_read_cache(DupeItem *di){	gchar *path;	CacheData *cd;	if (!di) return;	path = cache_find_location(CACHE_TYPE_SIM, di->path);	if (!path) return;	if (filetime(di->path) != filetime(path))		{		g_free(path);		return;		}	cd = cache_sim_data_load(path);	g_free(path);	if (cd)		{		if (!di->simd && cd->sim)			{			di->simd = cd->sim;			cd->sim = NULL;			}		if (di->width == 0 && di->height == 0 && cd->dimensions)			{			di->width = cd->width;			di->height = cd->height;			}		if (di->checksum == 0 && cd->have_checksum)			{			di->checksum = cd->checksum;			}		if (!di->md5sum && cd->have_md5sum)			{			di->md5sum = md5_digest_to_text(cd->md5sum);			}		cache_sim_data_free(cd);		}}static void dupe_item_write_cache(DupeItem *di){	gchar *base;	mode_t mode = 0755;	if (!di) return;	base = cache_get_location(CACHE_TYPE_SIM, di->path, FALSE, &mode);	if (cache_ensure_dir_exists(base, mode))		{		CacheData *cd;		cd = cache_sim_data_new();		cd->path = cache_get_location(CACHE_TYPE_SIM, di->path, TRUE, NULL);		if (di->width != 0) cache_sim_data_set_dimensions(cd, di->width, di->height);		if (di->checksum != 0) cache_sim_data_set_checksum(cd, di->checksum);		if (di->md5sum)			{			guchar digest[16];			if (md5_digest_from_text(di->md5sum, digest)) cache_sim_data_set_md5sum(cd, digest);			}		if (di->simd) cache_sim_data_set_similarity(cd, di->simd);		if (cache_sim_data_save(cd))			{			filetime_set(cd->path, filetime(di->path));			}		cache_sim_data_free(cd);		}	g_free(base);}/* * ------------------------------------------------------------------ * Window list utils * ------------------------------------------------------------------ */static gint dupe_listview_find_item(GtkListStore *store, DupeItem *item, GtkTreeIter *iter){	gint valid;	gint row = 0;	valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), iter);	while (valid)		{		DupeItem *item_n;		gtk_tree_model_get(GTK_TREE_MODEL(store), iter, DUPE_COLUMN_POINTER, &item_n, -1);		if (item_n == item) return row;		valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), iter);		row++;		}	return -1;}static void dupe_listview_add(DupeWindow *dw, DupeItem *parent, DupeItem *child){	DupeItem *di;	gint row;	gchar *text[DUPE_COLUMN_COUNT];	GtkListStore *store;	GtkTreeIter iter;	gboolean color_set = FALSE;	gint rank;	if (!parent) return;	store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(dw->listview)));	if (child)		{		DupeMatch *dm;		row = dupe_listview_find_item(store, parent, &iter);		gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, DUPE_COLUMN_COLOR, &color_set, -1);		row++;		if (child->group)			{			dm = child->group->data;			rank = (gint)floor(dm->rank);			}		else			{			rank = 1;			printf("NULL group in item!\n");			}		}	else		{		if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))			{			gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, DUPE_COLUMN_COLOR, &color_set, -1);			color_set = !color_set;			}		else			{			color_set = FALSE;			}		row = 0;		rank = 0;		}	di = (child) ? child : parent;	if (!child && dw->second_set)		{		text[DUPE_COLUMN_RANK] = g_strdup("[1]");		}	else if (rank == 0)		{		text[DUPE_COLUMN_RANK] = g_strdup((di->second) ? "(2)" : "");		}	else		{		text[DUPE_COLUMN_RANK] = g_strdup_printf("%d%s", rank, (di->second) ? " (2)" : "");		}	text[DUPE_COLUMN_THUMB] = "";	text[DUPE_COLUMN_NAME] = (gchar *)di->name;	text[DUPE_COLUMN_SIZE] = text_from_size(di->size);	text[DUPE_COLUMN_DATE] = (gchar *)text_from_time(di->date);	if (di->width > 0 && di->height > 0)		{		text[DUPE_COLUMN_DIMENSIONS] = g_strdup_printf("%d x %d", di->width, di->height);		}	else		{		text[DUPE_COLUMN_DIMENSIONS] = g_strdup("");		}	text[DUPE_COLUMN_PATH] = di->path;	text[DUPE_COLUMN_COLOR] = NULL;	gtk_list_store_insert(store, &iter, row);	gtk_list_store_set(store, &iter,				DUPE_COLUMN_POINTER, di,				DUPE_COLUMN_RANK, text[DUPE_COLUMN_RANK],				DUPE_COLUMN_THUMB, NULL,				DUPE_COLUMN_NAME, text[DUPE_COLUMN_NAME],				DUPE_COLUMN_SIZE, text[DUPE_COLUMN_SIZE],				DUPE_COLUMN_DATE, text[DUPE_COLUMN_DATE],				DUPE_COLUMN_DIMENSIONS, text[DUPE_COLUMN_DIMENSIONS],				DUPE_COLUMN_PATH, text[DUPE_COLUMN_PATH],				DUPE_COLUMN_COLOR, color_set,				-1);	g_free(text[DUPE_COLUMN_RANK]);	g_free(text[DUPE_COLUMN_SIZE]);	g_free(text[DUPE_COLUMN_DIMENSIONS]);}static void dupe_listview_populate(DupeWindow *dw){	GtkListStore *store;	GList *work;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -