view_file_list.c

来自「Gqview,Linux下基于GTK+库写成的轻量级而能丰富的图像浏览程序。」· C语言 代码 · 共 1,819 行 · 第 1/3 页

C
1,819
字号
	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));}static void vflist_populate_view(ViewFileList *vfl){	GtkListStore *store;	GtkTreeIter iter;	gint thumbs;	GList *work;	GtkTreeRowReference *visible_row = NULL;	GtkTreePath *tpath;	gint valid;	store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vfl->listview)));	thumbs = vfl->thumbs_enabled;	vflist_thumb_stop(vfl);	if (!vfl->list)		{		gtk_list_store_clear(store);		vflist_send_update(vfl);		return;		}	if (GTK_WIDGET_REALIZED(vfl->listview) &&	    gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vfl->listview), 0, 0, &tpath, NULL, NULL, NULL))		{		visible_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), tpath);		gtk_tree_path_free(tpath);		}	vflist_listview_set_height(vfl->listview, thumbs);	valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);	work = vfl->list;	while (work)		{		gint match;		FileData *fd = work->data;		gint done = FALSE;		while (!done)			{			FileData *old_fd = NULL;			if (valid)				{				gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);				match = CASE_SORT(fd->name, old_fd->name);				}			else				{				match = -1;				}			if (match < 0)				{				GtkTreeIter new;				gchar *size;				size = text_from_size(fd->size);				if (valid)					{					gtk_list_store_insert_before(store, &new, &iter);					}				else					{					gtk_list_store_append(store, &new);					}				gtk_list_store_set(store, &new, FILE_COLUMN_POINTER, fd,								FILE_COLUMN_THUMB, (thumbs) ? fd->pixbuf : NULL,								FILE_COLUMN_NAME, fd->name,								FILE_COLUMN_SIZE, size,								FILE_COLUMN_DATE, text_from_time(fd->date),								FILE_COLUMN_COLOR, FALSE, -1);				g_free(size);				done = TRUE;				}			else if (match > 0)				{				valid = gtk_list_store_remove(store, &iter);				}			else				{				gtk_list_store_set(store, &iter, FILE_COLUMN_POINTER, fd, -1);				if (fd->date != old_fd->date)					{					gchar *size;					/* update, file changed */					size = text_from_size(fd->size);					gtk_list_store_set(store, &iter, FILE_COLUMN_SIZE, size,									 FILE_COLUMN_DATE, text_from_time(fd->date), -1);					g_free(size);					}				else if (fd != old_fd)					{					/* preserve thumbnail */					if (fd->pixbuf) g_object_unref(fd->pixbuf);					fd->pixbuf = old_fd->pixbuf;					if (fd->pixbuf) g_object_ref(fd->pixbuf);					}				gtk_list_store_set(store, &iter, FILE_COLUMN_THUMB, (thumbs) ? fd->pixbuf : NULL, -1);				if (vfl->select_fd == old_fd) vfl->select_fd = fd;				if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);				done = TRUE;				}			}		work = work->next;		}	while (valid)		{		valid = gtk_list_store_remove(store, &iter);		}	if (visible_row)		{		if (gtk_tree_row_reference_valid(visible_row))			{			tpath = gtk_tree_row_reference_get_path(visible_row);			gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vfl->listview), tpath, NULL, TRUE, 0.0, 0.0);			gtk_tree_path_free(tpath);			}		gtk_tree_row_reference_free(visible_row);		}	vflist_send_update(vfl);	vflist_thumb_update(vfl);}gint vflist_refresh(ViewFileList *vfl){	GList *old_list;	gint ret = TRUE;	old_list = vfl->list;	vfl->list = NULL;	if (vfl->path)		{		ret = filelist_read(vfl->path, &vfl->list, NULL);		}	vfl->list = filelist_sort(vfl->list, vfl->sort_method, vfl->sort_ascend);	vflist_populate_view(vfl);	filelist_free(old_list);	return ret;}/* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */#define CELL_HEIGHT_OVERRIDE 512static 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 *vflist_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 vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,				     GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data){	ViewFileList *vfl = data;	gboolean set;	gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);	g_object_set(G_OBJECT(cell),		     "cell-background-gdk", vflist_listview_color_shifted(vfl->listview),		     "cell-background-set", set, NULL);}static void vflist_listview_add_column(ViewFileList *vfl, 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 (!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);		}	gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vfl, NULL);	gtk_tree_view_append_column(GTK_TREE_VIEW(vfl->listview), column);}/* *----------------------------------------------------------------------------- * base *----------------------------------------------------------------------------- */gint vflist_set_path(ViewFileList *vfl, const gchar *path){	GtkListStore *store;	if (!path) return FALSE;	if (vfl->path && strcmp(path, vfl->path) == 0) return TRUE;	g_free(vfl->path);	vfl->path = g_strdup(path);	/* force complete reload */	store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vfl->listview)));	gtk_list_store_clear(store);	filelist_free(vfl->list);	vfl->list = NULL;	return vflist_refresh(vfl);}static void vflist_destroy_cb(GtkWidget *widget, gpointer data){	ViewFileList *vfl = data;	if (vfl->popup)		{		g_signal_handlers_disconnect_matched(G_OBJECT(vfl->popup), G_SIGNAL_MATCH_DATA,						     0, 0, 0, NULL, vfl);		gtk_widget_destroy(vfl->popup);		}	vflist_select_idle_cancel(vfl);	vflist_thumb_stop(vfl);	g_free(vfl->path);	filelist_free(vfl->list);	g_free(vfl);}ViewFileList *vflist_new(const gchar *path, gint thumbs){	ViewFileList *vfl;	GtkListStore *store;	GtkTreeSelection *selection;	vfl = g_new0(ViewFileList, 1);	vfl->path = NULL;	vfl->list = NULL;	vfl->click_fd = NULL;	vfl->select_fd = NULL;	vfl->sort_method = SORT_NAME;	vfl->sort_ascend = TRUE;	vfl->thumbs_enabled = thumbs;	vfl->thumbs_running = FALSE;	vfl->thumbs_count = 0;	vfl->thumbs_loader = NULL;	vfl->thumbs_filedata = NULL;	vfl->select_idle_id = -1;	vfl->popup = NULL;	vfl->widget = gtk_scrolled_window_new(NULL, NULL);	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(vfl->widget), GTK_SHADOW_IN);	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(vfl->widget),				       GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);	g_signal_connect(G_OBJECT(vfl->widget), "destroy",			 G_CALLBACK(vflist_destroy_cb), vfl);	store = gtk_list_store_new(6, G_TYPE_POINTER, GDK_TYPE_PIXBUF, G_TYPE_STRING,				   G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);	vfl->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));	g_object_unref(store);	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vfl->listview));	gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);	gtk_tree_selection_set_select_function(selection, vflist_select_cb, vfl, NULL);	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vfl->listview), FALSE);	gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vfl->listview), FALSE);	vflist_listview_add_column(vfl, FILE_COLUMN_THUMB, "", TRUE, FALSE);	vflist_listview_add_column(vfl, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE);	vflist_listview_add_column(vfl, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE);	vflist_listview_add_column(vfl, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE);	g_signal_connect(G_OBJECT(vfl->listview), "key_press_event",			 G_CALLBACK(vflist_press_key_cb), vfl);	gtk_container_add (GTK_CONTAINER(vfl->widget), vfl->listview);	gtk_widget_show(vfl->listview);	vflist_dnd_init(vfl);	g_signal_connect(G_OBJECT(vfl->listview), "button_press_event",			 G_CALLBACK(vflist_press_cb), vfl);	g_signal_connect(G_OBJECT(vfl->listview), "button_release_event",			 G_CALLBACK(vflist_release_cb), vfl);	if (path) vflist_set_path(vfl, path);	return vfl;}void vflist_set_status_func(ViewFileList *vfl,			    void (*func)(ViewFileList *vfl, gpointer data), gpointer data){	vfl->func_status = func;	vfl->data_status = data;}void vflist_set_thumb_status_func(ViewFileList *vfl,				  void (*func)(ViewFileList *vfl, gdouble val, const gchar *text, gpointer data),				  gpointer data){	vfl->func_thumb_status = func;	vfl->data_thumb_status = data;}void vflist_thumb_set(ViewFileList *vfl, gint enable){	if (vfl->thumbs_enabled == enable) return;	vfl->thumbs_enabled = enable;	vflist_refresh(vfl);}void vflist_set_layout(ViewFileList *vfl, LayoutWindow *layout){	vfl->layout = layout;}/* *----------------------------------------------------------------------------- * maintenance (for rename, move, remove) *----------------------------------------------------------------------------- */static gint vflist_maint_find_closest(ViewFileList *vfl, gint row, gint count, GList *ignore_list){	GList *list = NULL;	GList *work;	gint rev = row - 1;	row ++;	work = ignore_list;	while (work)		{		gint f = vflist_index_by_path(vfl, work->data);		if (f >= 0) list = g_list_prepend(list, GINT_TO_POINTER(f));		work = work->next;		}	while (list)		{		gint c = TRUE;		work = list;		while (work && c)			{			gpointer p = work->data;			work = work->next;			if (row == GPOINTER_TO_INT(p))				{				row++;				c = FALSE;				}			if (rev == GPOINTER_TO_INT(p))				{				rev--;				c = FALSE;				}			if (!c) list = g_list_remove(list, p);			}		if (c && list)			{			g_list_free(list);			list = NULL;			}		}	if (row > count - 1)		{		if (rev < 0)			return -1;		else			return rev;		}	else		{		return row;		}}gint vflist_maint_renamed(ViewFileList *vfl, const gchar *source, const gchar *dest){	gint ret = FALSE;	gint row;	gchar *source_base;	gchar *dest_base;	GList *work;	FileData *fd;	row = vflist_index_by_path(vfl, source);	if (row < 0) return FALSE;	source_base = remove_level_from_path(source);	dest_base = remove_level_from_path(dest);	work = g_list_nth(vfl->list, row);	fd = work->data;	if (strcmp(source_base, dest_base) == 0)		{		GtkListStore *store;		GtkTreeIter iter;		GtkTreeIter position;		gint old_row;		gint n;		old_row = g_list_index(vfl->list, fd);		vfl->list = g_list_remove(vfl->list, fd);		g_free(fd->path);		fd->path = g_strdup(dest);		fd->name = filename_from_path(fd->path);		vfl->list = filelist_insert_sort(vfl->list, fd, vfl->sort_method, vfl->sort_ascend);		n = g_list_index(vfl->list, fd);		store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vfl->listview)));		row = vflist_find_row(vfl, fd, &iter);		if (vflist_find_row(vfl, fd, &iter) >= 0 &&		    gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &position, NULL, n))			{			if (old_row >= n)				{				gtk_list_store_move_before(store, &iter, &position);				}			else				{				gtk_list_store_move_after(store, &iter, &position);				}			}		gtk_list_store_set(store, &iter, FILE_COLUMN_NAME, fd->name, -1);		ret = TRUE;		}	else		{		ret = vflist_maint_removed(vfl, source, NULL);		}	g_free(source_base);	g_free(dest_base);	return ret;}gint vflist_maint_removed(ViewFileList *vfl, const gchar *path, GList *ignore_list){	GtkTreeIter iter;	GList *list;	FileData *fd;	gint row;	gint new_row = -1;	row = vflist_index_by_path(vfl, path);	if (row < 0) return FALSE;	if (vflist_index_is_selected(vfl, row) &&	    layout_image_get_collection(vfl->layout, NULL) == NULL)		{		gint n;		n = vflist_count(vfl, NULL);		if (ignore_list)			{			new_row = vflist_maint_find_closest(vfl, row, n, ignore_list);			if (debug) printf("row = %d, closest is %d\n", row, new_row);			}		else			{			if (row + 1 < n)				{				new_row = row + 1;				}			else if (row > 0)				{				new_row = row - 1;				}			}		vflist_select_none(vfl);		if (new_row >= 0)			{			fd = vflist_index_get_data(vfl, new_row);			if (vflist_find_row(vfl, fd, &iter) >= 0)				{				GtkTreeSelection *selection;				selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vfl->listview));				gtk_tree_selection_select_iter(selection, &iter);				vflist_move_cursor(vfl, &iter);				}			}		}	fd = vflist_index_get_data(vfl, row);	if (vflist_find_row(vfl, fd, &iter) >= 0)		{		GtkListStore *store;		store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vfl->listview)));		gtk_list_store_remove(store, &iter);		}	list = g_list_nth(vfl->list, row);	fd = list->data;	/* thumbnail loader check */	if (fd == vfl->thumbs_filedata) vfl->thumbs_filedata = NULL;	vfl->list = g_list_remove(vfl->list, fd);	file_data_free(fd);	vflist_send_update(vfl);	return TRUE;}gint vflist_maint_moved(ViewFileList *vfl, const gchar *source, const gchar *dest, GList *ignore_list){	gint ret = FALSE;	gchar *buf;	if (!source || !vfl->path) return FALSE;	buf = remove_level_from_path(source);	if (strcmp(buf, vfl->path) == 0)		{		ret = vflist_maint_removed(vfl, source, ignore_list);		}	g_free(buf);	return ret;}

⌨️ 快捷键说明

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