/*
- * Geeqie
- * (C) 2004 John Ellis
- * Copyright (C) 2008 The Geeqie Team
+ * Copyright (C) 2004 John Ellis
+ * Copyright (C) 2008 - 2016 The Geeqie Team
*
* 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!
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "main.h"
#include "view_file_list.h"
+#include "bar.h"
#include "cache_maint.h"
#include "dnd.h"
#include "editors.h"
#include "img-view.h"
-#include "info.h"
#include "layout.h"
#include "layout_image.h"
#include "menu.h"
+#include "metadata.h"
#include "thumb.h"
#include "utilops.h"
#include "ui_fileops.h"
FILE_COLUMN_POINTER = 0,
FILE_COLUMN_VERSION,
FILE_COLUMN_THUMB,
+ FILE_COLUMN_FORMATTED,
FILE_COLUMN_NAME,
- FILE_COLUMN_MULTILINE,
+ FILE_COLUMN_SIDECARS,
FILE_COLUMN_SIZE,
FILE_COLUMN_DATE,
+ FILE_COLUMN_EXPANDED,
FILE_COLUMN_COLOR,
FILE_COLUMN_MARKS,
FILE_COLUMN_MARKS_LAST = FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
FILE_VIEW_COLUMN_MARKS = 0,
FILE_VIEW_COLUMN_MARKS_LAST = FILE_VIEW_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
FILE_VIEW_COLUMN_THUMB,
- FILE_VIEW_COLUMN_MULTILINE,
- FILE_VIEW_COLUMN_NAME,
+ FILE_VIEW_COLUMN_FORMATTED,
FILE_VIEW_COLUMN_SIZE,
FILE_VIEW_COLUMN_DATE,
FILE_VIEW_COLUMN_COUNT
-static gint vflist_row_is_selected(ViewFile *vf, FileData *fd);
-static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data);
-static void vflist_populate_view(ViewFile *vf);
+static gboolean vflist_row_is_selected(ViewFile *vf, FileData *fd);
+static gboolean vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data);
+static void vflist_populate_view(ViewFile *vf, gboolean force);
+static gboolean vflist_is_multiline(ViewFile *vf);
+static void vflist_set_expanded(ViewFile *vf, GtkTreeIter *iter, gboolean expanded);
/*
typedef struct {
FileData *fd;
GtkTreeIter *iter;
- gint found;
+ gboolean found;
gint row;
} ViewFileFindRowData;
if (fd == find->fd)
{
*find->iter = *iter;
- find->found = 1;
+ find->found = TRUE;
return TRUE;
}
find->row++;
static gint vflist_find_row(ViewFile *vf, FileData *fd, GtkTreeIter *iter)
{
GtkTreeModel *store;
- ViewFileFindRowData data = {fd, iter, 0, 0};
+ ViewFileFindRowData data = {fd, iter, FALSE, 0};
store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
gtk_tree_model_foreach(store, vflist_find_row_cb, &data);
return -1;
}
-
-/*
-static gint vflist_find_sidecar_list_idx(GList *work, FileData *fd)
+static FileData *vflist_find_data_by_coord(ViewFile *vf, gint x, gint y, GtkTreeIter *iter)
{
- gint i = 0;
- while (work)
- {
- FileData *fd_p = work->data;
- if (fd == fd_p) return i;
+ GtkTreePath *tpath;
+ GtkTreeViewColumn *column;
- i++;
+ if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), x, y,
+ &tpath, &column, NULL, NULL))
+ {
+ GtkTreeModel *store;
+ GtkTreeIter row;
+ FileData *fd;
- GList *work2 = fd_p->sidecar_files;
- while (work2)
- {
- fd_p = work2->data;
- if (fd == fd_p) return i;
+ store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+ gtk_tree_model_get_iter(store, &row, tpath);
+ gtk_tree_path_free(tpath);
+ gtk_tree_model_get(store, &row, FILE_COLUMN_POINTER, &fd, -1);
- i++;
- work2 = work2->next;
- }
- work = work->next;
+ return fd;
}
- return -1;
-}
-*/
-
-static gint vflist_sidecar_list_count(GList *work)
-{
- gint i = 0;
- while (work)
- {
- FileData *fd = work->data;
- i++;
- GList *work2 = fd->sidecar_files;
- while (work2)
- {
- i++;
- work2 = work2->next;
- }
- work = work->next;
- }
- return i;
+ return NULL;
}
static gboolean vflist_store_clear_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
{
FileData *fd;
gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
+
+ /* it seems that gtk_tree_store_clear may call some callbacks
+ that use the column. Set the pointer to NULL to be safe. */
+ gtk_tree_store_set(GTK_TREE_STORE(model), iter, FILE_COLUMN_POINTER, NULL, -1);
file_data_unref(fd);
return FALSE;
}
-static void vflist_store_clear(ViewFile *vf)
+static void vflist_store_clear(ViewFile *vf, gboolean unlock_files)
{
GtkTreeModel *store;
+ GList *files = NULL;
+
+ if (unlock_files && vf->marks_enabled)
+ {
+ // unlock locked files in this directory
+ filelist_read(vf->dir_fd, &files, NULL);
+ while (files)
+ {
+ FileData *fd = files->data;
+ files = files->next;
+ file_data_unlock(fd);
+ file_data_unref(fd); // undo the ref that got added in filelist_read
+ }
+ }
+
+ g_list_free(files);
store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
gtk_tree_model_foreach(store, vflist_store_clear_cb, NULL);
gtk_tree_store_clear(GTK_TREE_STORE(store));
}
-void vflist_color_set(ViewFile *vf, FileData *fd, gint color_set)
+void vflist_color_set(ViewFile *vf, FileData *fd, gboolean color_set)
{
GtkTreeModel *store;
GtkTreeIter iter;
}
-static gint vflist_column_idx(ViewFile *vf, gint store_idx)
-{
- GList *columns, *work;
- gint i = 0;
-
- columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
- work = columns;
- while (work)
- {
- GtkTreeViewColumn *column = work->data;
- if (store_idx == GPOINTER_TO_INT(g_object_get_data (G_OBJECT(column), "column_store_idx")))
- break;
- work = work->next;
- i++;
- }
-
- g_list_free(columns);
- return i;
-}
-
-
/*
*-----------------------------------------------------------------------------
* dnd
{
ViewFile *vf = data;
GList *list = NULL;
- gchar *uri_text = NULL;
- gint total;
- if (!VFLIST_INFO(vf, click_fd)) return;
+ if (!VFLIST(vf)->click_fd) return;
- if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
+ if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
{
list = vf_selection_get_list(vf);
}
else
{
- list = g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
+ list = g_list_append(NULL, file_data_ref(VFLIST(vf)->click_fd));
}
if (!list) return;
-
- uri_text = uri_text_from_filelist(list, &total, (info == TARGET_TEXT_PLAIN));
+ uri_selection_data_set_uris_from_filelist(selection_data, list);
filelist_free(list);
-
- DEBUG_1(uri_text);
-
- gtk_selection_data_set(selection_data, selection_data->target,
- 8, (guchar *)uri_text, total);
- g_free(uri_text);
}
static void vflist_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
{
ViewFile *vf = data;
- vflist_color_set(vf, VFLIST_INFO(vf, click_fd), TRUE);
+ vflist_color_set(vf, VFLIST(vf)->click_fd, TRUE);
- if (VFLIST_INFO(vf, thumbs_enabled) &&
- VFLIST_INFO(vf, click_fd) && VFLIST_INFO(vf, click_fd)->thumb_pixbuf)
+ if (VFLIST(vf)->thumbs_enabled &&
+ VFLIST(vf)->click_fd && VFLIST(vf)->click_fd->thumb_pixbuf)
{
guint items;
- if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
+ if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
items = vf_selection_count(vf, NULL);
else
items = 1;
- dnd_set_drag_icon(widget, context, VFLIST_INFO(vf, click_fd)->thumb_pixbuf, items);
+ dnd_set_drag_icon(widget, context, VFLIST(vf)->click_fd->thumb_pixbuf, items);
}
}
{
ViewFile *vf = data;
- vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
+ vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
- if (context->action == GDK_ACTION_MOVE)
+ if (gdk_drag_context_get_selected_action(context) == GDK_ACTION_MOVE)
{
vf_refresh(vf);
}
}
+static void vflist_drag_data_received(GtkWidget *entry_widget, GdkDragContext *context,
+ int x, int y, GtkSelectionData *selection,
+ guint info, guint time, gpointer data)
+{
+ ViewFile *vf = data;
+
+ if (info == TARGET_TEXT_PLAIN) {
+ FileData *fd = vflist_find_data_by_coord(vf, x, y, NULL);
+
+ if (fd) {
+ /* Add keywords to file */
+ gchar *str = (gchar *) gtk_selection_data_get_text(selection);
+ GList *kw_list = string_to_keywords_list(str);
+
+ metadata_append_list(fd, KEYWORD_KEY, kw_list);
+ string_list_free(kw_list);
+ g_free(str);
+ }
+ }
+}
+
void vflist_dnd_init(ViewFile *vf)
{
gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
dnd_file_drag_types, dnd_file_drag_types_count,
GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
+ gtk_drag_dest_set(vf->listview, GTK_DEST_DEFAULT_ALL,
+ dnd_file_drag_types, dnd_file_drag_types_count,
+ GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
+
g_signal_connect(G_OBJECT(vf->listview), "drag_data_get",
G_CALLBACK(vflist_dnd_get), vf);
g_signal_connect(G_OBJECT(vf->listview), "drag_begin",
G_CALLBACK(vflist_dnd_begin), vf);
g_signal_connect(G_OBJECT(vf->listview), "drag_end",
G_CALLBACK(vflist_dnd_end), vf);
+ g_signal_connect(G_OBJECT(vf->listview), "drag_data_received",
+ G_CALLBACK(vflist_drag_data_received), vf);
}
/*
*-----------------------------------------------------------------------------
*/
+GList *vflist_selection_get_one(ViewFile *vf, FileData *fd)
+{
+ GList *list = g_list_append(NULL, file_data_ref(fd));
+
+ if (fd->sidecar_files)
+ {
+ /* check if the row is expanded */
+ GtkTreeModel *store;
+ GtkTreeIter iter;
+
+ store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+ if (vflist_find_row(vf, fd, &iter) >= 0)
+ {
+ GtkTreePath *tpath;
+
+ tpath = gtk_tree_model_get_path(store, &iter);
+ if (!gtk_tree_view_row_expanded(GTK_TREE_VIEW(vf->listview), tpath))
+ {
+ /* unexpanded - add whole group */
+ GList *work = fd->sidecar_files;
+ while (work)
+ {
+ FileData *sfd = work->data;
+ list = g_list_prepend(list, file_data_ref(sfd));
+ work = work->next;
+ }
+ }
+ gtk_tree_path_free(tpath);
+ }
+ list = g_list_reverse(list);
+ }
+
+ return list;
+}
+
GList *vflist_pop_menu_file_list(ViewFile *vf)
{
- if (!VFLIST_INFO(vf, click_fd)) return NULL;
+ if (!VFLIST(vf)->click_fd) return NULL;
- if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
+ if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
{
return vf_selection_get_list(vf);
}
-
- return g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
+ return vflist_selection_get_one(vf, VFLIST(vf)->click_fd);
}
+
void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data)
{
ViewFile *vf = data;
- if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
+ if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
{
GList *list;
}
else
{
- view_window_new(VFLIST_INFO(vf, click_fd));
+ view_window_new(VFLIST(vf)->click_fd);
}
}
list = vf_pop_menu_file_list(vf);
if (options->file_ops.enable_in_place_rename &&
- list && !list->next && VFLIST_INFO(vf, click_fd))
+ list && !list->next && VFLIST(vf)->click_fd)
{
GtkTreeModel *store;
GtkTreeIter iter;
filelist_free(list);
store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
- if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) >= 0)
+ if (vflist_find_row(vf, VFLIST(vf)->click_fd, &iter) >= 0)
{
GtkTreePath *tpath;
tpath = gtk_tree_model_get_path(store, &iter);
tree_edit_by_path(GTK_TREE_VIEW(vf->listview), tpath,
- vflist_column_idx(vf, FILE_COLUMN_NAME), VFLIST_INFO(vf, click_fd)->name,
+ FILE_VIEW_COLUMN_FORMATTED, VFLIST(vf)->click_fd->name,
vflist_row_rename_cb, vf);
gtk_tree_path_free(tpath);
}
{
ViewFile *vf = data;
- vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
+ vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
if (vf->layout)
{
- layout_thumb_set(vf->layout, !VFLIST_INFO(vf, thumbs_enabled));
+ layout_thumb_set(vf->layout, !VFLIST(vf)->thumbs_enabled);
}
else
{
- vflist_thumb_set(vf, !VFLIST_INFO(vf, thumbs_enabled));
+ vflist_thumb_set(vf, !VFLIST(vf)->thumbs_enabled);
}
}
{
ViewFile *vf = data;
- vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
+ vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
vf_refresh(vf);
+ gtk_tree_view_columns_autosize(GTK_TREE_VIEW(vf->listview));
}
void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data)
{
ViewFile *vf = data;
- vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
- VFLIST_INFO(vf, click_fd) = NULL;
+ vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
+ VFLIST(vf)->click_fd = NULL;
vf->popup = NULL;
}
*-----------------------------------------------------------------------------
*/
-static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
+static gboolean vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
{
ViewFile *vf = data;
- gchar *old_path;
gchar *new_path;
- if (strlen(new) == 0) return FALSE;
+ if (!new || !new[0]) return FALSE;
- old_path = g_build_filename(vf->dir_fd->path, old, NULL);
new_path = g_build_filename(vf->dir_fd->path, new, NULL);
if (strchr(new, G_DIR_SEPARATOR) != NULL)
file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
g_free(text);
}
- else if (isfile(new_path))
- {
- gchar *text = g_strdup_printf(_("A file with name %s already exists."), new);
- file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
- g_free(text);
- }
else
{
- FileData *fd = file_data_new_simple(old_path); /* get the fd from cache */
+ gchar *old_path = g_build_filename(vf->dir_fd->path, old, NULL);
+ FileData *fd = file_data_new_group(old_path); /* get the fd from cache */
file_util_rename_simple(fd, new_path, vf->listview);
file_data_unref(fd);
+ g_free(old_path);
}
- g_free(old_path);
+
g_free(new_path);
return FALSE;
GtkTreePath *tpath;
gint cw, ch;
- if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) < 0) return;
+ if (vflist_find_row(vf, VFLIST(vf)->click_fd, &iter) < 0) return;
store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
tpath = gtk_tree_model_get_path(store, &iter);
tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, FILE_COLUMN_NAME - 1, TRUE, x, y, &cw, &ch);
popup_menu_position_clamp(menu, x, y, 0);
}
-gint vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
+gboolean vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
{
ViewFile *vf = data;
GtkTreePath *tpath;
- if (event->keyval != GDK_Menu) return FALSE;
+ if (event->keyval != GDK_KEY_Menu) return FALSE;
gtk_tree_view_get_cursor(GTK_TREE_VIEW(vf->listview), &tpath, NULL);
if (tpath)
store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
gtk_tree_model_get_iter(store, &iter, tpath);
- gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, click_fd), -1);
+ gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST(vf)->click_fd, -1);
gtk_tree_path_free(tpath);
}
else
{
- VFLIST_INFO(vf, click_fd) = NULL;
+ VFLIST(vf)->click_fd = NULL;
}
vf->popup = vf_pop_menu(vf);
return TRUE;
}
-gint vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
+gboolean vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
{
ViewFile *vf = data;
GtkTreePath *tpath;
GtkTreeIter iter;
FileData *fd = NULL;
GtkTreeViewColumn *column;
-
+
vf->clicked_mark = 0;
if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
gtk_tree_model_get_iter(store, &iter, tpath);
gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
-#if 0
- gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE);
-#endif
gtk_tree_path_free(tpath);
}
- VFLIST_INFO(vf, click_fd) = fd;
+ VFLIST(vf)->click_fd = fd;
if (bevent->button == MOUSE_BUTTON_RIGHT)
{
gtk_widget_grab_focus(widget);
- /* returning FALSE and further processing of the event is needed for
+ /* returning FALSE and further processing of the event is needed for
correct operation of the expander, to show the sidecar files.
It however resets the selection of multiple files. With this condition
it should work for both cases */
return (gtk_tree_selection_count_selected_rows(selection) > 1);
}
-#if 0
if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_2BUTTON_PRESS)
{
if (vf->layout) layout_image_full_screen_start(vf->layout);
}
-#endif
return FALSE;
}
-gint vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
+gboolean vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
{
ViewFile *vf = data;
GtkTreePath *tpath;
if (bevent->button == MOUSE_BUTTON_MIDDLE)
{
- vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
+ vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
}
if (bevent->button != MOUSE_BUTTON_LEFT && bevent->button != MOUSE_BUTTON_MIDDLE)
if (bevent->button == MOUSE_BUTTON_MIDDLE)
{
- if (fd && VFLIST_INFO(vf, click_fd) == fd)
+ if (fd && VFLIST(vf)->click_fd == fd)
{
GtkTreeSelection *selection;
return TRUE;
}
- if (fd && VFLIST_INFO(vf, click_fd) == fd &&
+ if (fd && VFLIST(vf)->click_fd == fd &&
!(bevent->state & GDK_SHIFT_MASK ) &&
!(bevent->state & GDK_CONTROL_MASK ) &&
vflist_row_is_selected(vf, fd))
gtk_tree_selection_unselect_all(selection);
gtk_tree_selection_select_iter(selection, &iter);
vflist_move_cursor(vf, &iter);
-// return TRUE;// FIXME - expand
}
return FALSE;
FileData *read_ahead_fd = NULL;
gint row;
FileData *cur_fd;
+
if (!sel_fd) return;
cur_fd = layout_image_get_fd(vf->layout);
layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
}
-static gint vflist_select_idle_cb(gpointer data)
+static gboolean vflist_select_idle_cb(gpointer data)
{
ViewFile *vf = data;
if (!vf->layout)
{
- VFLIST_INFO(vf, select_idle_id) = -1;
+ VFLIST(vf)->select_idle_id = 0;
return FALSE;
}
vf_send_update(vf);
- if (VFLIST_INFO(vf, select_fd))
+ if (VFLIST(vf)->select_fd)
{
- vflist_select_image(vf, VFLIST_INFO(vf, select_fd));
- VFLIST_INFO(vf, select_fd) = NULL;
+ vflist_select_image(vf, VFLIST(vf)->select_fd);
+ VFLIST(vf)->select_fd = NULL;
}
- VFLIST_INFO(vf, select_idle_id) = -1;
+ VFLIST(vf)->select_idle_id = 0;
return FALSE;
}
static void vflist_select_idle_cancel(ViewFile *vf)
{
- if (VFLIST_INFO(vf, select_idle_id) != -1) g_source_remove(VFLIST_INFO(vf, select_idle_id));
- VFLIST_INFO(vf, select_idle_id) = -1;
+ if (VFLIST(vf)->select_idle_id)
+ {
+ g_source_remove(VFLIST(vf)->select_idle_id);
+ VFLIST(vf)->select_idle_id = 0;
+ }
}
static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
if (!path_currently_selected &&
gtk_tree_model_get_iter(store, &iter, tpath))
{
- gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, select_fd), -1);
+ gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST(vf)->select_fd, -1);
}
else
{
- VFLIST_INFO(vf, select_fd) = NULL;
+ VFLIST(vf)->select_fd = NULL;
}
if (vf->layout &&
- VFLIST_INFO(vf, select_idle_id) == -1)
+ !VFLIST(vf)->select_idle_id)
{
- VFLIST_INFO(vf, select_idle_id) = g_idle_add(vflist_select_idle_cb, vf);
+ VFLIST(vf)->select_idle_id = g_idle_add(vflist_select_idle_cb, vf);
}
return TRUE;
}
+static void vflist_expand_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data)
+{
+ ViewFile *vf = data;
+ vflist_set_expanded(vf, iter, TRUE);
+}
+
+static void vflist_collapse_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data)
+{
+ ViewFile *vf = data;
+ vflist_set_expanded(vf, iter, FALSE);
+}
+
/*
*-----------------------------------------------------------------------------
* misc
*-----------------------------------------------------------------------------
*/
-/*
-static gboolean vflist_dummy_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
- gboolean path_currently_selected, gpointer data)
+
+static gchar* vflist_get_formatted(ViewFile *vf, const gchar *name, const gchar *sidecars, const gchar *size, const gchar *time, gboolean expanded)
+ {
+ gboolean multiline = vflist_is_multiline(vf);
+ gchar *text;
+
+ if (multiline)
+ {
+ text = g_strdup_printf("%s %s\n%s\n%s", name, expanded ? "" : sidecars, size, time);
+ }
+ else
+ {
+ text = g_strdup_printf("%s %s", name, expanded ? "" : sidecars);
+ }
+ return text;
+}
+
+static void vflist_set_expanded(ViewFile *vf, GtkTreeIter *iter, gboolean expanded)
{
- return TRUE;
+ GtkTreeStore *store;
+ gchar *name;
+ gchar *sidecars;
+ gchar *size;
+ gchar *time;
+ gchar *formatted;
+
+ store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
+
+ gtk_tree_model_get(GTK_TREE_MODEL(store), iter,
+ FILE_COLUMN_NAME, &name,
+ FILE_COLUMN_SIDECARS, &sidecars,
+ FILE_COLUMN_SIZE, &size,
+ FILE_COLUMN_DATE, &time,
+ -1);
+ formatted = vflist_get_formatted(vf, name, sidecars, size, time, expanded);
+
+ gtk_tree_store_set(store, iter, FILE_COLUMN_FORMATTED, formatted,
+ FILE_COLUMN_EXPANDED, expanded,
+ -1);
+ g_free(time);
+ g_free(size);
+ g_free(sidecars);
+ g_free(name);
+ g_free(formatted);
}
-*/
static void vflist_setup_iter(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *iter, FileData *fd)
{
gchar *size;
gchar *sidecars = NULL;
- gchar *name_sidecars;
- gchar *multiline;
+ gchar *name;
const gchar *time = text_from_time(fd->date);
- name_sidecars = (gchar *)fd->name;
+ gchar *link = islink(fd->path) ? GQ_LINK_STR : "";
+ const gchar *disabled_grouping;
+ gchar *formatted;
+ gboolean expanded = FALSE;
- if (fd->sidecar_files)
+ if (fd->sidecar_files) /* expanded has no effect on files without sidecars */
{
- sidecars = file_data_sc_list_to_string(fd);
- name_sidecars = g_strdup_printf("%s %s", fd->name, sidecars);
+ gtk_tree_model_get(GTK_TREE_MODEL(store), iter, FILE_COLUMN_EXPANDED, &expanded, -1);
}
+
+ sidecars = file_data_sc_list_to_string(fd);
+
+ disabled_grouping = fd->disable_grouping ? _(" [NO GROUPING]") : "";
+ name = g_strdup_printf("%s%s%s", link, fd->name, disabled_grouping);
size = text_from_size(fd->size);
-
- multiline = g_strdup_printf("%s\n%s\n%s", name_sidecars, size, time);
+
+ formatted = vflist_get_formatted(vf, name, sidecars, size, time, expanded);
gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
FILE_COLUMN_VERSION, fd->version,
FILE_COLUMN_THUMB, fd->thumb_pixbuf,
- FILE_COLUMN_MULTILINE, multiline,
- FILE_COLUMN_NAME, name_sidecars,
+ FILE_COLUMN_FORMATTED, formatted,
+ FILE_COLUMN_SIDECARS, sidecars,
+ FILE_COLUMN_NAME, name,
FILE_COLUMN_SIZE, size,
FILE_COLUMN_DATE, time,
#define STORE_SET_IS_SLOW 1
-#if STORE_SET_IS_SLOW
+#if STORE_SET_IS_SLOW
/* this is 3x faster on a directory with 20000 files */
FILE_COLUMN_MARKS + 0, file_data_get_mark(fd, 0),
FILE_COLUMN_MARKS + 1, file_data_get_mark(fd, 1),
FILE_COLUMN_MARKS + 4, file_data_get_mark(fd, 4),
FILE_COLUMN_MARKS + 5, file_data_get_mark(fd, 5),
#if FILEDATA_MARKS_SIZE != 6
-#error this needs to be updated
+#error this needs to be updated
#endif
#endif
FILE_COLUMN_COLOR, FALSE, -1);
-#if !STORE_SET_IS_SLOW
+#if !STORE_SET_IS_SLOW
{
gint i;
for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
}
#endif
g_free(size);
- if (sidecars)
- {
- g_free(sidecars);
- g_free(name_sidecars);
- }
- g_free(multiline);
+ g_free(sidecars);
+ g_free(name);
+ g_free(formatted);
}
-static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected)
+static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected, gboolean force)
{
GList *work;
GtkTreeIter iter;
- gint valid;
+ gboolean valid;
gint num_ordered = 0;
gint num_prepended = 0;
{
gint match;
FileData *fd = work->data;
- gint done = FALSE;
+ gboolean done = FALSE;
while (!done)
{
if (valid)
{
- num_ordered++;
gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
FILE_COLUMN_POINTER, &old_fd,
FILE_COLUMN_VERSION, &old_version,
if (match == 0) g_warning("multiple fd for the same path");
}
-
+
}
else
{
if (valid)
{
+ num_ordered++;
gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
}
else
}
vflist_setup_iter(vf, store, &new, file_data_ref(fd));
- vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected);
-
+ vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected, force);
+
if (g_list_find(selected, fd))
{
/* renamed files - the same fd appears at different position - select it again*/
}
else
{
- if (fd->version != old_version)
+ num_ordered++;
+ if (fd->version != old_version || force)
{
vflist_setup_iter(vf, store, &iter, fd);
- vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected);
+ vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected, force);
}
if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
valid = gtk_tree_store_remove(store, &iter);
}
-
+
/* move the prepended entries to the correct position */
if (num_prepended)
{
gint i;
gint num_total = num_prepended + num_ordered;
gint *new_order = g_malloc(num_total * sizeof(gint));
-
+
for (i = 0; i < num_total; i++)
{
if (i < num_ordered)
}
}
-void vflist_sort_set(ViewFile *vf, SortType type, gint ascend)
+void vflist_sort_set(ViewFile *vf, SortType type, gboolean ascend)
{
gint i;
GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
*-----------------------------------------------------------------------------
*/
-static gint vflist_thumb_next(ViewFile *vf);
-static void vflist_thumb_progress_count(GList *list, gint *count, gint *done)
+void vflist_thumb_progress_count(GList *list, gint *count, gint *done)
{
GList *work = list;
while (work)
work = work->next;
if (fd->thumb_pixbuf) (*done)++;
-
- if (fd->sidecar_files)
+
+ if (fd->sidecar_files)
{
vflist_thumb_progress_count(fd->sidecar_files, count, done);
}
}
}
-static gdouble vflist_thumb_progress(ViewFile *vf)
-{
- gint count = 0;
- gint done = 0;
-
- vflist_thumb_progress_count(vf->list, &count, &done);
-
- DEBUG_1("thumb progress: %d of %d", done, count);
- return (gdouble)done / count;
-}
-
-
-static void vflist_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
-{
- if (vf->func_thumb_status)
- {
- vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
- }
-}
-
-static void vflist_thumb_cleanup(ViewFile *vf)
-{
- vflist_thumb_status(vf, 0.0, NULL);
-
- vf->thumbs_running = FALSE;
-
- thumb_loader_free(vf->thumbs_loader);
- vf->thumbs_loader = NULL;
-
- vf->thumbs_filedata = NULL;
-}
-
-static void vflist_thumb_stop(ViewFile *vf)
-{
- if (vf->thumbs_running) vflist_thumb_cleanup(vf);
-}
-
-static void vflist_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
+void vflist_set_thumb_fd(ViewFile *vf, FileData *fd)
{
GtkTreeStore *store;
GtkTreeIter iter;
store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->thumb_pixbuf, -1);
-
- vflist_thumb_status(vf, vflist_thumb_progress(vf), _("Loading thumbs..."));
}
-static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
-{
- ViewFile *vf = data;
-
- if (vf->thumbs_filedata && vf->thumbs_loader == tl)
- {
- vflist_thumb_do(vf, tl, vf->thumbs_filedata);
- }
-
- while (vflist_thumb_next(vf));
-}
-
-static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
-{
- ViewFile *vf = data;
-
- if (vf->thumbs_filedata && vf->thumbs_loader == tl)
- {
- vflist_thumb_do(vf, tl, vf->thumbs_filedata);
- }
-
- while (vflist_thumb_next(vf));
-}
-
-static gint vflist_thumb_next(ViewFile *vf)
+FileData *vflist_thumb_next_fd(ViewFile *vf)
{
GtkTreePath *tpath;
FileData *fd = NULL;
/* first check the visible files */
- if (GTK_WIDGET_REALIZED(vf->listview) &&
- gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
+ if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
{
GtkTreeModel *store;
GtkTreeIter iter;
- gint valid = TRUE;
+ gboolean valid = TRUE;
store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
gtk_tree_model_get_iter(store, &iter, tpath);
while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
{
- gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
- if (fd->thumb_pixbuf) fd = NULL;
+ FileData *nfd;
+
+ gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &nfd, -1);
+
+ if (!nfd->thumb_pixbuf) fd = nfd;
valid = gtk_tree_model_iter_next(store, &iter);
}
}
}
- if (!fd)
- {
- /* done */
- vflist_thumb_cleanup(vf);
- return FALSE;
- }
-
- vf->thumbs_filedata = fd;
-
- thumb_loader_free(vf->thumbs_loader);
+ return fd;
+}
- vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
- thumb_loader_set_callbacks(vf->thumbs_loader,
- vflist_thumb_done_cb,
- vflist_thumb_error_cb,
- NULL,
- vf);
- if (!thumb_loader_start(vf->thumbs_loader, fd))
+void vflist_thumb_reset_all(ViewFile *vf)
+{
+ GList *work = vf->list;
+ while (work)
{
- /* set icon to unknown, continue */
- DEBUG_1("thumb loader start failed %s", fd->path);
- vflist_thumb_do(vf, vf->thumbs_loader, fd);
-
- return TRUE;
+ FileData *fd = work->data;
+ if (fd->thumb_pixbuf)
+ {
+ g_object_unref(fd->thumb_pixbuf);
+ fd->thumb_pixbuf = NULL;
+ }
+ work = work->next;
}
-
- return FALSE;
-}
-
-static void vflist_thumb_update(ViewFile *vf)
-{
- vflist_thumb_stop(vf);
- if (!VFLIST_INFO(vf, thumbs_enabled)) return;
-
- vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
- vf->thumbs_running = TRUE;
-
- while (vflist_thumb_next(vf));
}
/*
return g_list_nth_data(vf->list, row);
}
-gint vflist_index_by_path(ViewFile *vf, const gchar *path)
+gint vflist_index_by_fd(ViewFile *vf, FileData *fd)
{
gint p = 0;
- GList *work;
-
- if (!path) return -1;
+ GList *work, *work2;
work = vf->list;
while (work)
{
- FileData *fd = work->data;
- if (strcmp(path, fd->path) == 0) return p;
-
+ FileData *list_fd = work->data;
+ if (list_fd == fd) return p;
+
+ work2 = list_fd->sidecar_files;
+ while (work2)
+ {
+ /* FIXME: return the same index also for sidecars
+ it is sufficient for next/prev navigation but it should be rewritten
+ without using indexes at all
+ */
+ FileData *sidecar_fd = work2->data;
+ if (sidecar_fd == fd) return p;
+ work2 = work2->next;
+ }
+
work = work->next;
p++;
}
*-----------------------------------------------------------------------------
*/
-static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
+static gboolean vflist_row_is_selected(ViewFile *vf, FileData *fd)
{
GtkTreeModel *store;
GtkTreeSelection *selection;
GList *slist;
GList *work;
- gint found = FALSE;
+ gboolean found = FALSE;
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
slist = gtk_tree_selection_get_selected_rows(selection, &store);
return found;
}
-gint vflist_index_is_selected(ViewFile *vf, gint row)
+gboolean vflist_index_is_selected(ViewFile *vf, gint row)
{
FileData *fd;
list = g_list_prepend(list, file_data_ref(fd));
+ if (!fd->parent && !gtk_tree_view_row_expanded(GTK_TREE_VIEW(vf->listview), tpath))
+ {
+ /* unexpanded - add whole group */
+ GList *work2 = fd->sidecar_files;
+ while (work2)
+ {
+ FileData *sfd = work2->data;
+ list = g_list_prepend(list, file_data_ref(sfd));
+ work2 = work2->next;
+ }
+ }
+
work = work->next;
}
g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
gtk_tree_selection_select_all(selection);
- VFLIST_INFO(vf, select_fd) = NULL;
+ VFLIST(vf)->select_fd = NULL;
}
void vflist_select_none(ViewFile *vf)
while (TRUE)
{
GtkTreeIter next = *iter;
-
+
if (gtk_tree_model_iter_next(store, &next))
*iter = next;
else
break;
}
-
+
return TRUE;
}
while (valid)
{
- gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
+ gboolean selected = gtk_tree_selection_iter_is_selected(selection, &iter);
if (selected)
gtk_tree_selection_unselect_iter(selection, &iter);
else
gtk_tree_selection_select_iter(selection, &iter);
-
+
valid = tree_model_iter_prev(store, &iter);
}
}
static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
{
GList *work;
-
+ FileData *fd = NULL;
+
if (sel_fd->parent) sel_fd = sel_fd->parent;
work = vf->list;
-
+
while (work)
{
gint match;
- FileData *fd = work->data;
+ fd = work->data;
work = work->next;
-
match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
-
- if (match >= 0)
- {
- vflist_select_by_fd(vf, fd);
- break;
- }
+
+ if (match >= 0) break;
}
+ if (fd) vflist_select_by_fd(vf, fd);
+
}
void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
GtkTreeModel *store;
GtkTreeIter iter;
GtkTreeSelection *selection;
- gint valid;
+ gboolean valid;
gint n = mark - 1;
g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
{
case MTS_MODE_SET: selected = mark_val;
break;
- case MTS_MODE_OR: selected = mark_val | selected;
+ case MTS_MODE_OR: selected = mark_val || selected;
break;
- case MTS_MODE_AND: selected = mark_val & selected;
+ case MTS_MODE_AND: selected = mark_val && selected;
break;
- case MTS_MODE_MINUS: selected = !mark_val & selected;
+ case MTS_MODE_MINUS: selected = !mark_val && selected;
break;
}
gtk_tree_model_get_iter(store, &iter, tpath);
gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
+ /* the change has a very limited range and the standard notification would trigger
+ complete re-read of the directory - try to do only minimal update instead */
file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
switch (mode)
case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
break;
}
-
- file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
- gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, file_data_get_mark(fd, n), -1);
+ if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
+ {
+ vf_refresh_idle(vf);
+ }
+ else
+ {
+ /* mark functions can have various side effects - update all columns to be sure */
+ vflist_setup_iter(vf, GTK_TREE_STORE(store), &iter, fd);
+ /* mark functions can change sidecars too */
+ vflist_setup_iter_recursive(vf, GTK_TREE_STORE(store), &iter, fd->sidecar_files, NULL, FALSE);
+ }
+
+
+ file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
work = work->next;
}
*-----------------------------------------------------------------------------
*/
-static void vflist_listview_set_columns(GtkWidget *listview, gint thumb)
+static void vflist_listview_set_columns(GtkWidget *listview, gboolean thumb, gboolean multiline)
{
GtkTreeViewColumn *column;
GtkCellRenderer *cell;
GList *list;
- gboolean multiline;
column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_THUMB);
if (!column) return;
gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 4);
- list = gtk_tree_view_column_get_cell_renderers(column);
+ list = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
if (!list) return;
cell = list->data;
g_list_free(list);
g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
gtk_tree_view_column_set_visible(column, thumb);
- multiline = (thumb && options->thumbnails.max_height >= 48);
-
- column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_MULTILINE);
+ column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_FORMATTED);
if (!column) return;
- gtk_tree_view_column_set_visible(column, multiline);
- if (multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
-
- column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_NAME);
- if (!column) return;
- gtk_tree_view_column_set_visible(column, !multiline);
- if (!multiline) gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
+ gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_SIZE);
if (!column) return;
column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_DATE);
if (!column) return;
gtk_tree_view_column_set_visible(column, !multiline);
+}
- gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
+static gboolean vflist_is_multiline(ViewFile *vf)
+{
+ return (VFLIST(vf)->thumbs_enabled && options->thumbnails.max_height >= 48);
}
-static void vflist_populate_view(ViewFile *vf)
+
+static void vflist_populate_view(ViewFile *vf, gboolean force)
{
GtkTreeStore *store;
- gint thumbs;
- GtkTreeRowReference *visible_row = NULL;
- GtkTreePath *tpath;
GList *selected;
store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
- thumbs = VFLIST_INFO(vf, thumbs_enabled);
- vflist_thumb_stop(vf);
+ vf_thumb_stop(vf);
if (!vf->list)
{
- vflist_store_clear(vf);
+ vflist_store_clear(vf, FALSE);
vf_send_update(vf);
return;
}
- if (GTK_WIDGET_REALIZED(vf->listview) &&
- gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->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_columns(vf->listview, thumbs);
+ vflist_listview_set_columns(vf->listview, VFLIST(vf)->thumbs_enabled, vflist_is_multiline(vf));
selected = vflist_selection_get_list(vf);
-
- vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
+
+ vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected, force);
if (selected && vflist_selection_count(vf, NULL) == 0)
{
/* all selected files disappeared */
vflist_select_closest(vf, selected->data);
- }
+ }
filelist_free(selected);
-
- 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(vf->listview), tpath, NULL, TRUE, 0.0, 0.0);
- gtk_tree_path_free(tpath);
- }
- gtk_tree_row_reference_free(visible_row);
- }
vf_send_update(vf);
- vflist_thumb_update(vf);
+ vf_thumb_update(vf);
}
-gint vflist_refresh(ViewFile *vf)
+gboolean vflist_refresh(ViewFile *vf)
{
GList *old_list;
- gint ret = TRUE;
+ gboolean ret = TRUE;
old_list = vf->list;
vf->list = NULL;
ret = filelist_read(vf->dir_fd, &vf->list, NULL);
+ if (vf->marks_enabled)
+ {
+ // When marks are enabled, lock FileDatas so that we don't end up re-parsing XML
+ // each time a mark is changed.
+ file_data_lock_list(vf->list);
+ }
+ else
+ {
+ // FIXME: only do this when needed (aka when we just switched from
+ // FIXME: marks-enabled to marks-disabled)
+ file_data_unlock_list(vf->list);
+ }
+
+ vf->list = file_data_filter_marks_list(vf->list, vf_marks_get_filter(vf));
file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
DEBUG_1("%s vflist_refresh: sort", get_exec_time());
DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
- vflist_populate_view(vf);
+ vflist_populate_view(vf, FALSE);
+
+ DEBUG_1("%s vflist_refresh: free filelist", get_exec_time());
filelist_free(old_list);
DEBUG_1("%s vflist_refresh: done", get_exec_time());
"cell-background-set", set, NULL);
}
-static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
+static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gboolean image, gboolean right_justify, gboolean expand)
{
GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
GtkTreeIter iter;
FileData *fd;
- gboolean mark;
+ gboolean marked;
guint col_idx;
store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
- return;
+ return;
col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
- gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
- mark = !mark;
- file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
- file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, mark);
+ gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &marked, -1);
+ marked = !marked;
+
+ /* the change has a very limited range and the standard notification would trigger
+ complete re-read of the directory - try to do only minimal update instead */
+ file_data_unregister_notify_func(vf_notify_cb, vf);
+ file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, marked);
+ if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
+ {
+ vf_refresh_idle(vf);
+ }
+ else
+ {
+ /* mark functions can have various side effects - update all columns to be sure */
+ vflist_setup_iter(vf, GTK_TREE_STORE(store), &iter, fd);
+ /* mark functions can change sidecars too */
+ vflist_setup_iter_recursive(vf, GTK_TREE_STORE(store), &iter, fd->sidecar_files, NULL, FALSE);
+ }
file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
- gtk_tree_store_set(store, &iter, col_idx, mark, -1);
gtk_tree_path_free(path);
}
{
GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
- GtkTreeStore *store;
- gint index;
-
- store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
renderer = gtk_cell_renderer_toggle_new();
column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
- index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
- gtk_tree_view_column_set_fixed_width(column, 18);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
+ gtk_tree_view_column_set_fixed_width(column, 22);
gtk_tree_view_column_set_visible(column, vf->marks_enabled);
*-----------------------------------------------------------------------------
*/
-gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
+gboolean vflist_set_fd(ViewFile *vf, FileData *dir_fd)
{
+ gboolean ret;
if (!dir_fd) return FALSE;
if (vf->dir_fd == dir_fd) return TRUE;
vf->dir_fd = file_data_ref(dir_fd);
/* force complete reload */
- vflist_store_clear(vf);
+ vflist_store_clear(vf, TRUE);
filelist_free(vf->list);
vf->list = NULL;
- return vf_refresh(vf);
+ ret = vf_refresh(vf);
+ gtk_tree_view_columns_autosize(GTK_TREE_VIEW(vf->listview));
+ return ret;
}
void vflist_destroy_cb(GtkWidget *widget, gpointer data)
vflist_select_idle_cancel(vf);
vf_refresh_idle_cancel(vf);
- vflist_thumb_stop(vf);
+ vf_thumb_stop(vf);
filelist_free(vf->list);
}
{
GtkTreeStore *store;
GtkTreeSelection *selection;
-
GType flist_types[FILE_COLUMN_COUNT];
gint i;
gint column;
vf->info = g_new0(ViewFileInfoList, 1);
-
- VFLIST_INFO(vf, click_fd) = NULL;
- VFLIST_INFO(vf, select_fd) = NULL;
- VFLIST_INFO(vf, thumbs_enabled) = FALSE;
-
- VFLIST_INFO(vf, select_idle_id) = -1;
flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
+ flist_types[FILE_COLUMN_FORMATTED] = G_TYPE_STRING;
flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
- flist_types[FILE_COLUMN_MULTILINE] = G_TYPE_STRING;
+ flist_types[FILE_COLUMN_SIDECARS] = G_TYPE_STRING;
flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
+ flist_types[FILE_COLUMN_EXPANDED] = G_TYPE_BOOLEAN;
flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
flist_types[i] = G_TYPE_BOOLEAN;
vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
g_object_unref(store);
+ g_signal_connect(G_OBJECT(vf->listview), "row-expanded",
+ G_CALLBACK(vflist_expand_cb), vf);
+
+ g_signal_connect(G_OBJECT(vf->listview), "row-collapsed",
+ G_CALLBACK(vflist_collapse_cb), vf);
+
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
{
- vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
- g_assert(column == FILE_VIEW_COLUMN_MARKS + i);
- column++;
- }
+ vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
+ g_assert(column == FILE_VIEW_COLUMN_MARKS + i);
+ column++;
+ }
vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
g_assert(column == FILE_VIEW_COLUMN_THUMB);
column++;
-
- vflist_listview_add_column(vf, FILE_COLUMN_MULTILINE, _("Name"), FALSE, FALSE, TRUE);
- g_assert(column == FILE_VIEW_COLUMN_MULTILINE);
- column++;
- vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, TRUE);
- g_assert(column == FILE_VIEW_COLUMN_NAME);
+ vflist_listview_add_column(vf, FILE_COLUMN_FORMATTED, _("Name"), FALSE, FALSE, TRUE);
+ g_assert(column == FILE_VIEW_COLUMN_FORMATTED);
column++;
vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
return vf;
}
-void vflist_thumb_set(ViewFile *vf, gint enable)
+void vflist_thumb_set(ViewFile *vf, gboolean enable)
{
- if (VFLIST_INFO(vf, thumbs_enabled) == enable) return;
+ if (VFLIST(vf)->thumbs_enabled == enable) return;
+
+ VFLIST(vf)->thumbs_enabled = enable;
- VFLIST_INFO(vf, thumbs_enabled) = enable;
- if (vf->layout) vf_refresh(vf);
+ /* vflist_populate_view is better than vf_refresh:
+ - no need to re-read the directory
+ - force update because the formatted string has changed
+ */
+ if (vf->layout)
+ {
+ vflist_populate_view(vf, TRUE);
+ gtk_tree_view_columns_autosize(GTK_TREE_VIEW(vf->listview));
+ }
}
-void vflist_marks_set(ViewFile *vf, gint enable)
+void vflist_marks_set(ViewFile *vf, gboolean enable)
{
GList *columns, *work;
gtk_tree_view_column_set_visible(column, enable);
}
+ if (enable)
+ {
+ // Previously disabled, which means that vf->list is complete
+ file_data_lock_list(vf->list);
+ }
+ else
+ {
+ // Previously enabled, which means that vf->list is incomplete
+ }
+
g_list_free(columns);
- //vf_refresh(vf);
}
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */