/* $Id: thunar-details-view.c 22700 2006-08-09 20:42:50Z benny $ */
/*-
* Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
*
* 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., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gdk/gdkkeysyms.h>
#include <thunar/thunar-column-editor.h>
#include <thunar/thunar-details-view.h>
#include <thunar/thunar-details-view-ui.h>
#include <thunar/thunar-gtk-extensions.h>
#include <thunar/thunar-private.h>
#include <thunar/thunar-text-renderer.h>
/* Property identifiers */
enum
{
PROP_0,
PROP_FIXED_COLUMNS,
};
static void thunar_details_view_class_init (ThunarDetailsViewClass *klass);
static void thunar_details_view_init (ThunarDetailsView *details_view);
static void thunar_details_view_finalize (GObject *object);
static void thunar_details_view_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static void thunar_details_view_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static AtkObject *thunar_details_view_get_accessible (GtkWidget *widget);
static void thunar_details_view_connect_ui_manager (ThunarStandardView *standard_view,
GtkUIManager *ui_manager);
static void thunar_details_view_disconnect_ui_manager (ThunarStandardView *standard_view,
GtkUIManager *ui_manager);
static GList *thunar_details_view_get_selected_items (ThunarStandardView *standard_view);
static void thunar_details_view_select_all (ThunarStandardView *standard_view);
static void thunar_details_view_unselect_all (ThunarStandardView *standard_view);
static void thunar_details_view_select_path (ThunarStandardView *standard_view,
GtkTreePath *path);
static void thunar_details_view_set_cursor (ThunarStandardView *standard_view,
GtkTreePath *path,
gboolean start_editing);
static void thunar_details_view_scroll_to_path (ThunarStandardView *standard_view,
GtkTreePath *path,
gboolean use_align,
gfloat row_align,
gfloat col_align);
static GtkTreePath *thunar_details_view_get_path_at_pos (ThunarStandardView *standard_view,
gint x,
gint y);
static gboolean thunar_details_view_get_visible_range (ThunarStandardView *standard_view,
GtkTreePath **start_path,
GtkTreePath **end_path);
static void thunar_details_view_highlight_path (ThunarStandardView *standard_view,
GtkTreePath *path);
static void thunar_details_view_notify_model (GtkTreeView *tree_view,
GParamSpec *pspec,
ThunarDetailsView *details_view);
static void thunar_details_view_notify_width (GtkTreeViewColumn *tree_view_column,
GParamSpec *pspec,
ThunarDetailsView *details_view);
static gboolean thunar_details_view_button_press_event (GtkTreeView *tree_view,
GdkEventButton *event,
ThunarDetailsView *details_view);
static gboolean thunar_details_view_key_press_event (GtkTreeView *tree_view,
GdkEventKey *event,
ThunarDetailsView *details_view);
static void thunar_details_view_row_activated (GtkTreeView *tree_view,
GtkTreePath *path,
GtkTreeViewColumn *column,
ThunarDetailsView *details_view);
static void thunar_details_view_columns_changed (ThunarColumnModel *column_model,
ThunarDetailsView *details_view);
static void thunar_details_view_zoom_level_changed (ThunarDetailsView *details_view);
static void thunar_details_view_action_setup_columns (GtkAction *action,
ThunarDetailsView *details_view);
struct _ThunarDetailsViewClass
{
ThunarStandardViewClass __parent__;
};
struct _ThunarDetailsView
{
ThunarStandardView __parent__;
/* the column model */
ThunarColumnModel *column_model;
/* the tree view columns */
GtkTreeViewColumn *columns[THUNAR_N_VISIBLE_COLUMNS];
/* whether to use fixed column widths */
gboolean fixed_columns;
/* the UI manager merge id for the details view */
guint ui_merge_id;
};
static const GtkActionEntry action_entries[] =
{
{ "setup-columns", NULL, N_ ("Configure _Columns..."), NULL, N_ ("Configure the columns in the detailed list view"), G_CALLBACK (thunar_details_view_action_setup_columns), },
};
static GObjectClass *thunar_details_view_parent_class;
GType
thunar_details_view_get_type (void)
{
static GType type = G_TYPE_INVALID;
if (G_UNLIKELY (type == G_TYPE_INVALID))
{
static const GTypeInfo info =
{
sizeof (ThunarDetailsViewClass),
NULL,
NULL,
(GClassInitFunc) thunar_details_view_class_init,
NULL,
NULL,
sizeof (ThunarDetailsView),
0,
(GInstanceInitFunc) thunar_details_view_init,
NULL,
};
type = g_type_register_static (THUNAR_TYPE_STANDARD_VIEW, I_("ThunarDetailsView"), &info, 0);
}
return type;
}
static void
thunar_details_view_class_init (ThunarDetailsViewClass *klass)
{
ThunarStandardViewClass *thunarstandard_view_class;
GtkWidgetClass *gtkwidget_class;
GObjectClass *gobject_class;
/* determine the parent type class */
thunar_details_view_parent_class = g_type_class_peek_parent (klass);
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = thunar_details_view_finalize;
gobject_class->get_property = thunar_details_view_get_property;
gobject_class->set_property = thunar_details_view_set_property;
gtkwidget_class = GTK_WIDGET_CLASS (klass);
gtkwidget_class->get_accessible = thunar_details_view_get_accessible;
thunarstandard_view_class = THUNAR_STANDARD_VIEW_CLASS (klass);
thunarstandard_view_class->connect_ui_manager = thunar_details_view_connect_ui_manager;
thunarstandard_view_class->disconnect_ui_manager = thunar_details_view_disconnect_ui_manager;
thunarstandard_view_class->get_selected_items = thunar_details_view_get_selected_items;
thunarstandard_view_class->select_all = thunar_details_view_select_all;
thunarstandard_view_class->unselect_all = thunar_details_view_unselect_all;
thunarstandard_view_class->select_path = thunar_details_view_select_path;
thunarstandard_view_class->set_cursor = thunar_details_view_set_cursor;
thunarstandard_view_class->scroll_to_path = thunar_details_view_scroll_to_path;
thunarstandard_view_class->get_path_at_pos = thunar_details_view_get_path_at_pos;
thunarstandard_view_class->get_visible_range = thunar_details_view_get_visible_range;
thunarstandard_view_class->highlight_path = thunar_details_view_highlight_path;
thunarstandard_view_class->zoom_level_property_name = "last-details-view-zoom-level";
/**
* ThunarDetailsView:fixed-columns:
*
* %TRUE to use fixed column widths.
**/
g_object_class_install_property (gobject_class,
PROP_FIXED_COLUMNS,
g_param_spec_boolean ("fixed-columns",
"fixed-columns",
"fixed-columns",
FALSE,
EXO_PARAM_READWRITE));
}
static void
thunar_details_view_init (ThunarDetailsView *details_view)
{
GtkTreeSelection *selection;
GtkCellRenderer *right_aligned_renderer;
GtkCellRenderer *left_aligned_renderer;
GtkCellRenderer *renderer;
ThunarColumn column;
GtkWidget *tree_view;
/* we need to force the GtkTreeView to recalculate column sizes
* whenever the zoom-level changes, so we connect a handler here.
*/
g_signal_connect (G_OBJECT (details_view), "notify::zoom-level", G_CALLBACK (thunar_details_view_zoom_level_changed), NULL);
/* setup the details view actions */
gtk_action_group_add_actions (THUNAR_STANDARD_VIEW (details_view)->action_group,
action_entries, G_N_ELEMENTS (action_entries),
GTK_WIDGET (details_view));
/* create the tree view to embed */
tree_view = exo_tree_view_new ();
g_signal_connect (G_OBJECT (tree_view), "notify::model",
G_CALLBACK (thunar_details_view_notify_model), details_view);
g_signal_connect (G_OBJECT (tree_view), "button-press-event",
G_CALLBACK (thunar_details_view_button_press_event), details_view);
g_signal_connect (G_OBJECT (tree_view), "key-press-event",
G_CALLBACK (thunar_details_view_key_press_event), details_view);
g_signal_connect (G_OBJECT (tree_view), "row-activated",
G_CALLBACK (thunar_details_view_row_activated), details_view);
gtk_container_add (GTK_CONTAINER (details_view), tree_view);
gtk_widget_show (tree_view);
/* configure general aspects of the details view */
gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tree_view), TRUE);
gtk_tree_view_set_enable_search (GTK_TREE_VIEW (tree_view), TRUE);
/* enable rubberbanding (if supported) */
#if GTK_CHECK_VERSION(2,9,0)
gtk_tree_view_set_rubber_banding (GTK_TREE_VIEW (tree_view), TRUE);
#endif
/* connect to the default column model */
details_view->column_model = thunar_column_model_get_default ();
g_signal_connect (G_OBJECT (details_view->column_model), "columns-changed", G_CALLBACK (thunar_details_view_columns_changed), details_view);
/* allocate the shared right-aligned text renderer */
right_aligned_renderer = g_object_new (THUNAR_TYPE_TEXT_RENDERER, "xalign", 1.0f, NULL);
exo_gtk_object_ref_sink (GTK_OBJECT (right_aligned_renderer));
/* allocate the shared left-aligned text renderer */
left_aligned_renderer = g_object_new (THUNAR_TYPE_TEXT_RENDERER, "xalign", 0.0f, NULL);
exo_gtk_object_ref_sink (GTK_OBJECT (left_aligned_renderer));
/* allocate the tree view columns */
for (column = 0; column < THUNAR_N_VISIBLE_COLUMNS; ++column)
{
/* allocate the tree view column */
details_view->columns[column] = gtk_tree_view_column_new ();
exo_gtk_object_ref_sink (GTK_OBJECT (details_view->columns[column]));
gtk_tree_view_column_set_min_width (details_view->columns[column], 50);
gtk_tree_view_column_set_resizable (details_view->columns[column], TRUE);
gtk_tree_view_column_set_sort_column_id (details_view->columns[column], column);
gtk_tree_view_column_set_title (details_view->columns[column], thunar_column_model_get_column_name (details_view->column_model, column));
/* stay informed whenever the width of the column is changed */
g_signal_connect (G_OBJECT (details_view->columns[column]), "notify::width", G_CALLBACK (thunar_details_view_notify_width), details_view);
/* name column gets special renderers */
if (G_UNLIKELY (column == THUNAR_COLUMN_NAME))
{
/* add the icon renderer */
gtk_tree_view_column_pack_start (details_view->columns[column], THUNAR_STANDARD_VIEW (details_view)->icon_renderer, FALSE);
gtk_tree_view_column_set_attributes (details_view->columns[column], THUNAR_STANDARD_VIEW (details_view)->icon_renderer,
"file", THUNAR_COLUMN_FILE,
NULL);
/* add the name renderer */
g_object_set (G_OBJECT (THUNAR_STANDARD_VIEW (details_view)->name_renderer), "xalign", 0.0, NULL);
gtk_tree_view_column_pack_start (details_view->columns[column], THUNAR_STANDARD_VIEW (details_view)->name_renderer, TRUE);
gtk_tree_view_column_set_attributes (details_view->columns[column], THUNAR_STANDARD_VIEW (details_view)->name_renderer,
"text", THUNAR_COLUMN_NAME,
NULL);
/* add some spacing between the icon and the name */
gtk_tree_view_column_set_spacing (details_view->columns[column], 2);
}
else
{
/* size is right aligned, everything else is left aligned */
renderer = (column == THUNAR_COLUMN_SIZE) ? right_aligned_renderer : left_aligned_renderer;
/* add the renderer */
gtk_tree_view_column_pack_start (details_view->columns[column], renderer, TRUE);
gtk_tree_view_column_set_attributes (details_view->columns[column], renderer, "text", column, NULL);
}
/* append the tree view column to the tree view */
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), details_view->columns[column]);
}
/* configure the tree selection */
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
g_signal_connect_swapped (G_OBJECT (selection), "changed",
G_CALLBACK (thunar_standard_view_selection_changed), details_view);
/* apply the initial column order and visibility from the column model */
thunar_details_view_columns_changed (details_view->column_model, details_view);
/* synchronize the "fixed-columns" property */
exo_binding_new (G_OBJECT (THUNAR_STANDARD_VIEW (details_view)->preferences),
"last-details-view-fixed-columns",
G_OBJECT (details_view),
"fixed-columns");
/* apply fixed column widths if we start in fixed column mode */
if (G_UNLIKELY (details_view->fixed_columns))
{
/* apply to all columns */
for (column = 0; column < THUNAR_N_VISIBLE_COLUMNS; ++column)
gtk_tree_view_column_set_fixed_width (details_view->columns[column], thunar_column_model_get_column_width (details_view->column_model, column));
}
/* release the shared text renderers */
g_object_unref (G_OBJECT (right_aligned_renderer));
g_object_unref (G_OBJECT (left_aligned_renderer));
}
static void
thunar_details_view_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ThunarDetailsView *details_view = THUNAR_DETAILS_VIEW (object);
switch (prop_id)
{
case PROP_FIXED_COLUMNS:
g_value_set_boolean (value, thunar_details_view_get_fixed_columns (details_view));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
thunar_details_view_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ThunarDetailsView *details_view = THUNAR_DETAILS_VIEW (object);
switch (prop_id)
{
case PROP_FIXED_COLUMNS:
thunar_details_view_set_fixed_columns (details_view, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
thunar_details_view_finalize (GObject *object)
{
ThunarDetailsView *details_view = THUNAR_DETAILS_VIEW (object);
ThunarColumn column;
/* release the tree view columns array */
for (column = 0; column < THUNAR_N_VISIBLE_COLUMNS; ++column)
g_object_unref (G_OBJECT (details_view->columns[column]));
/* disconnect from the default column model */
g_signal_handlers_disconnect_by_func (G_OBJECT (details_view->column_model), thunar_details_view_columns_changed, details_view);
g_object_unref (G_OBJECT (details_view->column_model));
(*G_OBJECT_CLASS (thunar_details_view_parent_class)->finalize) (object);
}
static AtkObject*
thunar_details_view_get_accessible (GtkWidget *widget)
{
AtkObject *object;
/* query the atk object for the tree view class */
object = (*GTK_WIDGET_CLASS (thunar_details_view_parent_class)->get_accessible) (widget);
/* set custom Atk properties for the details view */
if (G_LIKELY (object != NULL))
{
atk_object_set_description (object, _("Detailed directory listing"));
atk_object_set_name (object, _("Details view"));
atk_object_set_role (object, ATK_ROLE_DIRECTORY_PANE);
}
return object;
}
static void
thunar_details_view_connect_ui_manager (ThunarStandardView *standard_view,
GtkUIManager *ui_manager)
{
ThunarDetailsView *details_view = THUNAR_DETAILS_VIEW (standard_view);
GError *error = NULL;
details_view->ui_merge_id = gtk_ui_manager_add_ui_from_string (ui_manager, thunar_details_view_ui,
thunar_details_view_ui_length, &error);
if (G_UNLIKELY (details_view->ui_merge_id == 0))
{
g_error ("Failed to merge ThunarDetailsView menus: %s", error->message);
g_error_free (error);
}
}
static void
thunar_details_view_disconnect_ui_manager (ThunarStandardView *standard_view,
GtkUIManager *ui_manager)
{
gtk_ui_manager_remove_ui (ui_manager, THUNAR_DETAILS_VIEW (standard_view)->ui_merge_id);
}
static GList*
thunar_details_view_get_selected_items (ThunarStandardView *standard_view)
{
GtkTreeSelection *selection;
_thunar_return_val_if_fail (THUNAR_IS_DETAILS_VIEW (standard_view), NULL);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (GTK_BIN (standard_view)->child));
return gtk_tree_selection_get_selected_rows (selection, NULL);
}
static void
thunar_details_view_select_all (ThunarStandardView *standard_view)
{
GtkTreeSelection *selection;
_thunar_return_if_fail (THUNAR_IS_DETAILS_VIEW (standard_view));
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (GTK_BIN (standard_view)->child));
gtk_tree_selection_select_all (selection);
}
static void
thunar_details_view_unselect_all (ThunarStandardView *standard_view)
{
GtkTreeSelection *selection;
_thunar_return_if_fail (THUNAR_IS_DETAILS_VIEW (standard_view));
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (GTK_BIN (standard_view)->child));
gtk_tree_selection_unselect_all (selection);
}
static void
thunar_details_view_select_path (ThunarStandardView *standard_view,
GtkTreePath *path)
{
GtkTreeSelection *selection;
_thunar_return_if_fail (THUNAR_IS_DETAILS_VIEW (standard_view));
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (GTK_BIN (standard_view)->child));
gtk_tree_selection_select_path (selection, path);
}
static void
thunar_details_view_set_cursor (ThunarStandardView *standard_view,
GtkTreePath *path,
gboolean start_editing)
{
GtkCellRendererMode mode;
GtkTreeViewColumn *column;
_thunar_return_if_fail (THUNAR_IS_DETAILS_VIEW (standard_view));
/* make sure the name renderer is editable */
mode = standard_view->name_renderer->mode;
standard_view->name_renderer->mode = GTK_CELL_RENDERER_MODE_EDITABLE;
/* tell the tree view to start editing the given row */
column = gtk_tree_view_get_column (GTK_TREE_VIEW (GTK_BIN (standard_view)->child), 0);
gtk_tree_view_set_cursor_on_cell (GTK_TREE_VIEW (GTK_BIN (standard_view)->child),
path, column, standard_view->name_renderer,
start_editing);
/* reset the name renderer mode */
standard_view->name_renderer->mode = mode;
}
static void
thunar_details_view_scroll_to_path (ThunarStandardView *standard_view,
GtkTreePath *path,
gboolean use_align,
gfloat row_align,
gfloat col_align)
{
GtkTreeViewColumn *column;
_thunar_return_if_fail (THUNAR_IS_DETAILS_VIEW (standard_view));
/* tell the tree view to scroll to the given row */
column = gtk_tree_view_get_column (GTK_TREE_VIEW (GTK_BIN (standard_view)->child), 0);
gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (GTK_BIN (standard_view)->child), path, column, use_align, row_align, col_align);
}
static GtkTreePath*
thunar_details_view_get_path_at_pos (ThunarStandardView *standard_view,
gint x,
gint y)
{
GtkTreePath *path;
_thunar_return_val_if_fail (THUNAR_IS_DETAILS_VIEW (standard_view), NULL);
if (gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (GTK_BIN (standard_view)->child), x, y, &path, NULL))
return path;
return NULL;
}
static gboolean
thunar_details_view_get_visible_range (ThunarStandardView *standard_view,
GtkTreePath **start_path,
GtkTreePath **end_path)
{
_thunar_return_val_if_fail (THUNAR_IS_DETAILS_VIEW (standard_view), FALSE);
#if GTK_CHECK_VERSION(2,8,0)
return gtk_tree_view_get_visible_range (GTK_TREE_VIEW (GTK_BIN (standard_view)->child), start_path, end_path);
#else
return FALSE;
#endif
}
static void
thunar_details_view_highlight_path (ThunarStandardView *standard_view,
GtkTreePath *path)
{
_thunar_return_if_fail (THUNAR_IS_DETAILS_VIEW (standard_view));
gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (GTK_BIN (standard_view)->child), path, GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
}
static void
thunar_details_view_notify_model (GtkTreeView *tree_view,
GParamSpec *pspec,
ThunarDetailsView *details_view)
{
/* We need to set the search column here, as GtkTreeView resets it
* whenever a new model is set.
*/
gtk_tree_view_set_search_column (tree_view, THUNAR_COLUMN_NAME);
}
static void
thunar_details_view_notify_width (GtkTreeViewColumn *tree_view_column,
GParamSpec *pspec,
ThunarDetailsView *details_view)
{
ThunarColumn column;
_thunar_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_view_column));
_thunar_return_if_fail (THUNAR_IS_DETAILS_VIEW (details_view));
/* lookup the column no for the given tree view column */
for (column = 0; column < THUNAR_N_VISIBLE_COLUMNS; ++column)
if (details_view->columns[column] == tree_view_column)
{
/* save the new width as default fixed width */
thunar_column_model_set_column_width (details_view->column_model, column, gtk_tree_view_column_get_width (tree_view_column));
break;
}
}
static gboolean
thunar_details_view_button_press_event (GtkTreeView *tree_view,
GdkEventButton *event,
ThunarDetailsView *details_view)
{
GtkTreeSelection *selection;
GtkTreePath *path;
GtkTreeIter iter;
ThunarFile *file;
GtkAction *action;
/* check if the event is for the bin window */
if (G_UNLIKELY (event->window != gtk_tree_view_get_bin_window (tree_view)))
return FALSE;
/* we unselect all selected items if the user clicks on an empty
* area of the treeview and no modifier key is active.
*/
if ((event->state & gtk_accelerator_get_default_mod_mask ()) == 0
&& !gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y, NULL, NULL, NULL, NULL))
{
selection = gtk_tree_view_get_selection (tree_view);
gtk_tree_selection_unselect_all (selection);
}
/* open the context menu on right clicks */
if (event->type == GDK_BUTTON_PRESS && event->button == 3)
{
selection = gtk_tree_view_get_selection (tree_view);
if (gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y, &path, NULL, NULL, NULL))
{
/* select the path on which the user clicked if not selected yet */
if (!gtk_tree_selection_path_is_selected (selection, path))
{
/* we don't unselect all other items if Control is active */
if ((event->state & GDK_CONTROL_MASK) == 0)
gtk_tree_selection_unselect_all (selection);
gtk_tree_selection_select_path (selection, path);
}
gtk_tree_path_free (path);
/* queue the menu popup */
thunar_standard_view_queue_popup (THUNAR_STANDARD_VIEW (details_view), event);
}
else
{
/* open the context menu */
thunar_standard_view_context_menu (THUNAR_STANDARD_VIEW (details_view), event->button, event->time);
}
return TRUE;
}
else if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_2BUTTON_PRESS) && event->button == 2)
{
/* determine the path to the item that was middle-clicked */
if (gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y, &path, NULL, NULL, NULL))
{
/* select only the path to the item on which the user clicked */
selection = gtk_tree_view_get_selection (tree_view);
gtk_tree_selection_unselect_all (selection);
gtk_tree_selection_select_path (selection, path);
/* if the event was a double-click or we are in single-click mode, then
* we'll open the file or folder (folder's are opened in new windows)
*/
if (G_LIKELY (event->type == GDK_2BUTTON_PRESS || exo_tree_view_get_single_click (EXO_TREE_VIEW (tree_view))))
{
/* determine the file for the path */
gtk_tree_model_get_iter (GTK_TREE_MODEL (THUNAR_STANDARD_VIEW (details_view)->model), &iter, path);
file = thunar_list_model_get_file (THUNAR_STANDARD_VIEW (details_view)->model, &iter);
if (G_LIKELY (file != NULL))
{
/* determine the action to perform depending on the type of the file */
action = thunar_gtk_ui_manager_get_action_by_name (THUNAR_STANDARD_VIEW (details_view)->ui_manager,
thunar_file_is_directory (file) ? "open-in-new-window" : "open");
/* emit the action */
if (G_LIKELY (action != NULL))
gtk_action_activate (action);
/* release the file reference */
g_object_unref (G_OBJECT (file));
}
}
/* cleanup */
gtk_tree_path_free (path);
}
return TRUE;
}
return FALSE;
}
static gboolean
thunar_details_view_key_press_event (GtkTreeView *tree_view,
GdkEventKey *event,
ThunarDetailsView *details_view)
{
/* popup context menu if "Menu" or "<Shift>F10" is pressed */
if (event->keyval == GDK_Menu || ((event->state & GDK_SHIFT_MASK) != 0 && event->keyval == GDK_F10))
{
thunar_standard_view_context_menu (THUNAR_STANDARD_VIEW (details_view), 0, event->time);
return TRUE;
}
return FALSE;
}
static void
thunar_details_view_row_activated (GtkTreeView *tree_view,
GtkTreePath *path,
GtkTreeViewColumn *column,
ThunarDetailsView *details_view)
{
GtkTreeSelection *selection;
GtkAction *action;
_thunar_return_if_fail (THUNAR_IS_DETAILS_VIEW (details_view));
/* be sure to have only the double clicked item selected */
selection = gtk_tree_view_get_selection (tree_view);
gtk_tree_selection_unselect_all (selection);
gtk_tree_selection_select_path (selection, path);
/* emit the "open" action */
action = thunar_gtk_ui_manager_get_action_by_name (THUNAR_STANDARD_VIEW (details_view)->ui_manager, "open");
if (G_LIKELY (action != NULL))
gtk_action_activate (action);
}
static void
thunar_details_view_columns_changed (ThunarColumnModel *column_model,
ThunarDetailsView *details_view)
{
const ThunarColumn *column_order;
ThunarColumn column;
_thunar_return_if_fail (THUNAR_IS_DETAILS_VIEW (details_view));
_thunar_return_if_fail (THUNAR_IS_COLUMN_MODEL (column_model));
_thunar_return_if_fail (details_view->column_model == column_model);
/* determine the new column order */
column_order = thunar_column_model_get_column_order (column_model);
/* apply new order and visibility */
for (column = 0; column < THUNAR_N_VISIBLE_COLUMNS; ++column)
{
/* apply the new visibility for the tree view column */
gtk_tree_view_column_set_visible (details_view->columns[column], thunar_column_model_get_column_visible (column_model, column));
/* change the order of the column relative to its predecessor */
if (G_LIKELY (column > 0))
{
gtk_tree_view_move_column_after (GTK_TREE_VIEW (GTK_BIN (details_view)->child),
details_view->columns[column_order[column]],
details_view->columns[column_order[column - 1]]);
}
}
}
static void
thunar_details_view_zoom_level_changed (ThunarDetailsView *details_view)
{
ThunarColumn column;
_thunar_return_if_fail (THUNAR_IS_DETAILS_VIEW (details_view));
/* determine the list of tree view columns */
for (column = 0; column < THUNAR_N_VISIBLE_COLUMNS; ++column)
{
#if GTK_CHECK_VERSION(2,8,0)
/* just queue a resize on this column */
gtk_tree_view_column_queue_resize (details_view->columns[column]);
#else
/* determine the renderers for this column */
GList *renderers = gtk_tree_view_column_get_cell_renderers (details_view->columns[column]);
if (G_LIKELY (renderers != NULL))
{
/* this is really an awfull hack, but it works! It forces GtkTreeView to recalculate
* the dimensions of this column, and that's all that matters. We don't use it with
* newer Gtk+ versions either, so what the f*ck...
*/
gtk_tree_view_column_set_cell_data_func (details_view->columns[column], renderers->data, NULL, NULL, NULL);
g_list_free (renderers);
}
#endif
}
}
static void
thunar_details_view_action_setup_columns (GtkAction *action,
ThunarDetailsView *details_view)
{
_thunar_return_if_fail (THUNAR_IS_DETAILS_VIEW (details_view));
_thunar_return_if_fail (GTK_IS_ACTION (action));
/* popup the column editor dialog */
thunar_show_column_editor (details_view);
}
/**
* thunar_details_view_new:
*
* Allocates a new #ThunarDetailsView instance, which is not
* associated with any #ThunarListModel yet.
*
* Return value: the newly allocated #ThunarDetailsView instance.
**/
GtkWidget*
thunar_details_view_new (void)
{
return g_object_new (THUNAR_TYPE_DETAILS_VIEW, NULL);
}
/**
* thunar_details_view_get_fixed_columns:
* @details_view : a #ThunarDetailsView.
*
* Returns %TRUE if @details_view uses fixed column widths.
*
* Return value: %TRUE if @details_view uses fixed column widths.
**/
gboolean
thunar_details_view_get_fixed_columns (ThunarDetailsView *details_view)
{
_thunar_return_val_if_fail (THUNAR_IS_DETAILS_VIEW (details_view), FALSE);
return details_view->fixed_columns;
}
/**
* thunar_details_view_set_fixed_columns:
* @details_view : a #ThunarDetailsView.
* @fixed_columns : %TRUE to use fixed column widths.
*
* Applies @fixed_columns to @details_view.
**/
void
thunar_details_view_set_fixed_columns (ThunarDetailsView *details_view,
gboolean fixed_columns)
{
ThunarColumn column;
gint width;
_thunar_return_if_fail (THUNAR_IS_DETAILS_VIEW (details_view));
/* normalize the value */
fixed_columns = !!fixed_columns;
/* check if we have a new value */
if (G_LIKELY (details_view->fixed_columns != fixed_columns))
{
/* apply the new value */
details_view->fixed_columns = fixed_columns;
/* apply the new setting to all columns */
for (column = 0; column < THUNAR_N_VISIBLE_COLUMNS; ++column)
{
/* apply the new column mode */
if (G_LIKELY (fixed_columns))
{
/* apply "width" as "fixed-width" for fixed columns mode */
width = gtk_tree_view_column_get_width (details_view->columns[column]);
if (G_UNLIKELY (width <= 0))
width = thunar_column_model_get_column_width (details_view->column_model, column);
gtk_tree_view_column_set_fixed_width (details_view->columns[column], MAX (width, 1));
/* set column to fixed width */
gtk_tree_view_column_set_sizing (details_view->columns[column], GTK_TREE_VIEW_COLUMN_FIXED);
}
else
{
/* reset column to grow-only mode */
gtk_tree_view_column_set_sizing (details_view->columns[column], GTK_TREE_VIEW_COLUMN_GROW_ONLY);
}
}
/* for fixed columns mode, we can enable the fixed height
* mode to improve the performance of the GtkTreeVeiw.
*/
gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (GTK_BIN (details_view)->child), fixed_columns);
/* notify listeners */
g_object_notify (G_OBJECT (details_view), "fixed-columns");
}
}