thunar-usagebars/thunar/thunar-column-model.c

1070 lines
32 KiB
C
Raw Normal View History

/* vi:set et ai sw=2 sts=2 ts=2: */
/*-
* Copyright (c) 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
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "thunar/thunar-column-model.h"
#include "thunar/thunar-preferences.h"
#include "thunar/thunar-private.h"
#include <libxfce4util/libxfce4util.h>
/* Signal identifiers */
enum
{
COLUMNS_CHANGED,
LAST_SIGNAL,
};
static void
thunar_column_model_tree_model_init (GtkTreeModelIface *iface);
static void
thunar_column_model_finalize (GObject *object);
static GtkTreeModelFlags
thunar_column_model_get_flags (GtkTreeModel *tree_model);
static gint
thunar_column_model_get_n_columns (GtkTreeModel *tree_model);
static GType
thunar_column_model_get_column_type (GtkTreeModel *tree_model,
gint idx);
static gboolean
thunar_column_model_get_iter (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreePath *path);
static GtkTreePath *
thunar_column_model_get_path (GtkTreeModel *tree_model,
GtkTreeIter *iter);
static void
thunar_column_model_get_value (GtkTreeModel *tree_model,
GtkTreeIter *iter,
gint idx,
GValue *value);
static gboolean
thunar_column_model_iter_next (GtkTreeModel *tree_model,
GtkTreeIter *iter);
static gboolean
thunar_column_model_iter_children (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent);
static gboolean
thunar_column_model_iter_has_child (GtkTreeModel *tree_model,
GtkTreeIter *iter);
static gint
thunar_column_model_iter_n_children (GtkTreeModel *tree_model,
GtkTreeIter *iter);
static gboolean
thunar_column_model_iter_nth_child (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent,
gint n);
static gboolean
thunar_column_model_iter_parent (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *child);
static void
thunar_column_model_load_column_order (ThunarColumnModel *column_model);
static void
thunar_column_model_save_column_order (ThunarColumnModel *column_model);
static void
thunar_column_model_notify_column_order (ThunarPreferences *preferences,
GParamSpec *pspec,
ThunarColumnModel *column_model);
static void
thunar_column_model_load_column_widths (ThunarColumnModel *column_model);
static void
thunar_column_model_save_column_widths (ThunarColumnModel *column_model);
static void
thunar_column_model_notify_column_widths (ThunarPreferences *preferences,
GParamSpec *pspec,
ThunarColumnModel *column_model);
static void
thunar_column_model_load_visible_columns (ThunarColumnModel *column_model);
static void
thunar_column_model_save_visible_columns (ThunarColumnModel *column_model);
static void
thunar_column_model_notify_visible_columns (ThunarPreferences *preferences,
GParamSpec *pspec,
ThunarColumnModel *column_model);
static gboolean
thunar_column_model_set_column_width_timer (gpointer user_data);
struct _ThunarColumnModelClass
{
GObjectClass __parent__;
/* signals */
void (*columns_changed) (ThunarColumnModel *column_model);
};
struct _ThunarColumnModel
{
GObject __parent__;
/* the model stamp is only used when debugging is
* enabled, to make sure we don't accept iterators
* generated by another model.
*/
#ifndef NDEBUG
gint stamp;
#endif
ThunarPreferences *preferences;
ThunarColumn order[THUNAR_N_VISIBLE_COLUMNS];
gboolean visible[THUNAR_N_VISIBLE_COLUMNS];
gint width[THUNAR_N_VISIBLE_COLUMNS];
guint save_width_timer_id;
};
static guint column_model_signals[LAST_SIGNAL];
G_DEFINE_TYPE_WITH_CODE (ThunarColumnModel, thunar_column_model, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, thunar_column_model_tree_model_init))
static void
thunar_column_model_class_init (ThunarColumnModelClass *klass)
{
GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = thunar_column_model_finalize;
/**
* ThunarColumnModel::columns-changed:
* @column_model : a #ThunarColumnModel.
*
* Emitted by @column_model whenever the
* order of the columns or the visibility
* of a column in @column_model is changed.
**/
column_model_signals[COLUMNS_CHANGED] =
g_signal_new (I_ ("columns-changed"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ThunarColumnModelClass, columns_changed),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
thunar_column_model_tree_model_init (GtkTreeModelIface *iface)
{
iface->get_flags = thunar_column_model_get_flags;
iface->get_n_columns = thunar_column_model_get_n_columns;
iface->get_column_type = thunar_column_model_get_column_type;
iface->get_iter = thunar_column_model_get_iter;
iface->get_path = thunar_column_model_get_path;
iface->get_value = thunar_column_model_get_value;
iface->iter_next = thunar_column_model_iter_next;
iface->iter_children = thunar_column_model_iter_children;
iface->iter_has_child = thunar_column_model_iter_has_child;
iface->iter_n_children = thunar_column_model_iter_n_children;
iface->iter_nth_child = thunar_column_model_iter_nth_child;
iface->iter_parent = thunar_column_model_iter_parent;
}
static void
thunar_column_model_init (ThunarColumnModel *column_model)
{
/* grab a reference on the preferences */
column_model->preferences = thunar_preferences_get ();
g_signal_connect (G_OBJECT (column_model->preferences), "notify::last-details-view-column-order",
G_CALLBACK (thunar_column_model_notify_column_order), column_model);
g_signal_connect (G_OBJECT (column_model->preferences), "notify::last-details-view-column-widths",
G_CALLBACK (thunar_column_model_notify_column_widths), column_model);
g_signal_connect (G_OBJECT (column_model->preferences), "notify::last-details-view-visible-columns",
G_CALLBACK (thunar_column_model_notify_visible_columns), column_model);
/* generate a random stamp if we're in debug mode */
#ifndef NDEBUG
column_model->stamp = g_random_int ();
#endif
/* load the column order */
thunar_column_model_load_column_order (column_model);
/* load the column widths */
thunar_column_model_load_column_widths (column_model);
/* load the list of visible columns */
thunar_column_model_load_visible_columns (column_model);
column_model->save_width_timer_id = 0;
}
static void
thunar_column_model_finalize (GObject *object)
{
ThunarColumnModel *column_model = THUNAR_COLUMN_MODEL (object);
/* disconnect from the global preferences */
g_signal_handlers_disconnect_by_data (G_OBJECT (column_model->preferences), column_model);
g_object_unref (G_OBJECT (column_model->preferences));
/* drop any running "save width" timer */
if (G_UNLIKELY (column_model->save_width_timer_id != 0))
g_source_remove (column_model->save_width_timer_id);
(*G_OBJECT_CLASS (thunar_column_model_parent_class)->finalize) (object);
}
static GtkTreeModelFlags
thunar_column_model_get_flags (GtkTreeModel *tree_model)
{
return GTK_TREE_MODEL_LIST_ONLY;
}
static gint
thunar_column_model_get_n_columns (GtkTreeModel *tree_model)
{
return THUNAR_COLUMN_MODEL_N_COLUMNS;
}
static GType
thunar_column_model_get_column_type (GtkTreeModel *tree_model,
gint idx)
{
switch (idx)
{
case THUNAR_COLUMN_MODEL_COLUMN_NAME:
return G_TYPE_STRING;
case THUNAR_COLUMN_MODEL_COLUMN_MUTABLE:
return G_TYPE_BOOLEAN;
case THUNAR_COLUMN_MODEL_COLUMN_VISIBLE:
return G_TYPE_BOOLEAN;
case THUNAR_COLUMN_MODEL_COLUMN_TOOLTIP:
return G_TYPE_STRING;
}
_thunar_assert_not_reached ();
return G_TYPE_INVALID;
}
static gboolean
thunar_column_model_get_iter (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreePath *path)
{
ThunarColumn column;
_thunar_return_val_if_fail (THUNAR_IS_COLUMN_MODEL (tree_model), FALSE);
_thunar_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
/* check if the path is valid */
column = gtk_tree_path_get_indices (path)[0];
if (G_UNLIKELY (column >= THUNAR_N_VISIBLE_COLUMNS))
return FALSE;
/* generate an iterator */
GTK_TREE_ITER_INIT (*iter, THUNAR_COLUMN_MODEL (tree_model)->stamp, GINT_TO_POINTER (column));
return TRUE;
}
static GtkTreePath *
thunar_column_model_get_path (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
_thunar_return_val_if_fail (THUNAR_IS_COLUMN_MODEL (tree_model), NULL);
_thunar_return_val_if_fail (iter->stamp == THUNAR_COLUMN_MODEL (tree_model)->stamp, NULL);
/* generate the path for the iterator */
return gtk_tree_path_new_from_indices (GPOINTER_TO_INT (iter->user_data), -1);
}
static void
thunar_column_model_get_value (GtkTreeModel *tree_model,
GtkTreeIter *iter,
gint idx,
GValue *value)
{
ThunarColumnModel *column_model = THUNAR_COLUMN_MODEL (tree_model);
ThunarColumn column;
_thunar_return_if_fail (THUNAR_IS_COLUMN_MODEL (column_model));
_thunar_return_if_fail (idx < THUNAR_COLUMN_MODEL_N_COLUMNS);
_thunar_return_if_fail (iter->stamp == column_model->stamp);
/* determine the column from the iterator */
column = GPOINTER_TO_INT (iter->user_data);
/* resolve the column according to the order */
column = column_model->order[column];
switch (idx)
{
case THUNAR_COLUMN_MODEL_COLUMN_NAME:
g_value_init (value, G_TYPE_STRING);
g_value_set_static_string (value, thunar_column_model_get_column_name (column_model, column));
break;
case THUNAR_COLUMN_MODEL_COLUMN_MUTABLE:
g_value_init (value, G_TYPE_BOOLEAN);
g_value_set_boolean (value, (column != THUNAR_COLUMN_NAME && !thunar_column_is_special (column)));
break;
case THUNAR_COLUMN_MODEL_COLUMN_VISIBLE:
g_value_init (value, G_TYPE_BOOLEAN);
g_value_set_boolean (value, thunar_column_model_get_column_visible (column_model, column));
break;
case THUNAR_COLUMN_MODEL_COLUMN_TOOLTIP:
g_value_init (value, G_TYPE_STRING);
if (thunar_column_is_special (column))
g_value_set_static_string (value, _("This column is reserved for special locations"));
break;
default:
_thunar_assert_not_reached ();
break;
}
}
static gboolean
thunar_column_model_iter_next (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
ThunarColumn column;
_thunar_return_val_if_fail (THUNAR_IS_COLUMN_MODEL (tree_model), FALSE);
_thunar_return_val_if_fail (iter->stamp == THUNAR_COLUMN_MODEL (tree_model)->stamp, FALSE);
/* move the iterator to the next column */
column = GPOINTER_TO_INT (iter->user_data) + 1;
iter->user_data = GINT_TO_POINTER (column);
/* check if the iterator is still valid */
return (column < THUNAR_N_VISIBLE_COLUMNS);
}
static gboolean
thunar_column_model_iter_children (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent)
{
_thunar_return_val_if_fail (THUNAR_IS_COLUMN_MODEL (tree_model), FALSE);
if (G_LIKELY (parent == NULL))
{
GTK_TREE_ITER_INIT (*iter, THUNAR_COLUMN_MODEL (tree_model)->stamp, GINT_TO_POINTER (0));
return TRUE;
}
return FALSE;
}
static gboolean
thunar_column_model_iter_has_child (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
return FALSE;
}
static gint
thunar_column_model_iter_n_children (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
_thunar_return_val_if_fail (THUNAR_IS_COLUMN_MODEL (tree_model), 0);
return (iter == NULL) ? THUNAR_N_VISIBLE_COLUMNS : 0;
}
static gboolean
thunar_column_model_iter_nth_child (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent,
gint n)
{
_thunar_return_val_if_fail (THUNAR_IS_COLUMN_MODEL (tree_model), FALSE);
if (G_LIKELY (parent == NULL && n < THUNAR_N_VISIBLE_COLUMNS))
{
GTK_TREE_ITER_INIT (*iter, THUNAR_COLUMN_MODEL (tree_model)->stamp, GINT_TO_POINTER (n));
return TRUE;
}
return FALSE;
}
static gboolean
thunar_column_model_iter_parent (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *child)
{
return FALSE;
}
static void
thunar_column_model_load_column_order (ThunarColumnModel *column_model)
{
ThunarColumn column;
GEnumClass *klass;
GEnumValue *value;
gchar **column_order;
gchar *tmp;
gint i, j;
/* determine the column order from the preferences */
g_object_get (G_OBJECT (column_model->preferences), "last-details-view-column-order", &tmp, NULL);
column_order = g_strsplit (tmp, ",", -1);
g_free (tmp);
/* reset the column order to its default */
for (j = 0; j < THUNAR_N_VISIBLE_COLUMNS; ++j)
column_model->order[j] = j;
/* now rearrange the columns according to the preferences */
klass = g_type_class_ref (THUNAR_TYPE_COLUMN);
for (i = 0; column_order[i] != NULL; ++i)
{
/* determine the enum value for the name */
value = g_enum_get_value_by_name (klass, column_order[i]);
if (G_UNLIKELY (value == NULL || value->value == i))
continue;
/* find the current position of the value */
for (j = 0; j < THUNAR_N_VISIBLE_COLUMNS; ++j)
if (column_model->order[j] == (guint) value->value)
break;
/* check if valid */
if (G_LIKELY (j < THUNAR_N_VISIBLE_COLUMNS))
{
/* exchange the positions of i and j */
column = column_model->order[i];
column_model->order[i] = column_model->order[j];
column_model->order[j] = column;
}
}
g_type_class_unref (klass);
/* release the column order */
g_strfreev (column_order);
}
static void
thunar_column_model_save_column_order (ThunarColumnModel *column_model)
{
GEnumClass *klass;
GEnumValue *value;
GString *column_order;
gint n;
/* allocate a string for the column order */
column_order = g_string_sized_new (256);
/* transform the internal visible column list */
klass = g_type_class_ref (THUNAR_TYPE_COLUMN);
for (n = 0; n < THUNAR_N_VISIBLE_COLUMNS; ++n)
{
/* append a comma if not empty */
if (*column_order->str != '\0')
g_string_append_c (column_order, ',');
/* append the enum value name */
value = g_enum_get_value (klass, column_model->order[n]);
g_string_append (column_order, value->value_name);
}
g_type_class_unref (klass);
/* save the list of visible columns */
g_signal_handlers_block_by_func (G_OBJECT (column_model->preferences), thunar_column_model_notify_column_order, column_model);
g_object_set (G_OBJECT (column_model->preferences), "last-details-view-column-order", column_order->str, NULL);
g_signal_handlers_unblock_by_func (G_OBJECT (column_model->preferences), thunar_column_model_notify_column_order, column_model);
/* release the string */
g_string_free (column_order, TRUE);
}
static void
thunar_column_model_notify_column_order (ThunarPreferences *preferences,
GParamSpec *pspec,
ThunarColumnModel *column_model)
{
GtkTreePath *path;
GtkTreeIter iter;
gint n;
_thunar_return_if_fail (THUNAR_IS_COLUMN_MODEL (column_model));
_thunar_return_if_fail (THUNAR_IS_PREFERENCES (preferences));
/* load the new column order */
thunar_column_model_load_column_order (column_model);
/* emit "row-changed" for all rows */
for (n = 0; n < THUNAR_N_VISIBLE_COLUMNS; ++n)
{
path = gtk_tree_path_new_from_indices (n, -1);
if (gtk_tree_model_get_iter (GTK_TREE_MODEL (column_model), &iter, path))
gtk_tree_model_row_changed (GTK_TREE_MODEL (column_model), path, &iter);
gtk_tree_path_free (path);
}
/* emit "columns-changed" */
g_signal_emit (G_OBJECT (column_model), column_model_signals[COLUMNS_CHANGED], 0);
}
static void
thunar_column_model_load_column_widths (ThunarColumnModel *column_model)
{
gchar **column_widths;
gchar *tmp;
gint width;
gint n;
/* determine the column widths from the preferences */
g_object_get (G_OBJECT (column_model->preferences), "last-details-view-column-widths", &tmp, NULL);
column_widths = g_strsplit (tmp, ",", -1);
g_free (tmp);
/* reset the column widths for the model */
for (n = 0; n < THUNAR_N_VISIBLE_COLUMNS; ++n)
column_model->width[n] = 50;
column_model->width[THUNAR_COLUMN_NAME] = 200;
/* parse the widths from the preferences */
for (n = 0; (n < THUNAR_N_VISIBLE_COLUMNS) && (column_widths[n] != NULL); ++n)
{
width = strtol (column_widths[n], NULL, 10);
if (G_LIKELY (width >= 0))
column_model->width[n] = width;
}
/* release the column width array */
g_strfreev (column_widths);
}
static void
thunar_column_model_save_column_widths (ThunarColumnModel *column_model)
{
GString *column_widths;
gint n;
/* allocate a string for the column widths */
column_widths = g_string_sized_new (96);
/* transform the column widths to a string */
for (n = 0; n < THUNAR_N_VISIBLE_COLUMNS; ++n)
{
/* append a comma if not empty */
if (*column_widths->str != '\0')
g_string_append_c (column_widths, ',');
/* append the width */
g_string_append_printf (column_widths, "%d", column_model->width[n]);
}
/* save the column widths */
g_signal_handlers_block_by_func (G_OBJECT (column_model->preferences), thunar_column_model_notify_column_widths, column_model);
g_object_set (G_OBJECT (column_model->preferences), "last-details-view-column-widths", column_widths->str, NULL);
g_signal_handlers_unblock_by_func (G_OBJECT (column_model->preferences), thunar_column_model_notify_column_widths, column_model);
/* release the string */
g_string_free (column_widths, TRUE);
}
static void
thunar_column_model_notify_column_widths (ThunarPreferences *preferences,
GParamSpec *pspec,
ThunarColumnModel *column_model)
{
_thunar_return_if_fail (THUNAR_IS_COLUMN_MODEL (column_model));
_thunar_return_if_fail (THUNAR_IS_PREFERENCES (preferences));
/* load the new column widths */
thunar_column_model_load_column_widths (column_model);
}
static void
thunar_column_model_load_visible_columns (ThunarColumnModel *column_model)
{
GEnumClass *klass;
GEnumValue *value;
gchar **visible_columns;
gchar *tmp;
gint n;
/* determine the list of visible columns from the preferences */
g_object_get (G_OBJECT (column_model->preferences), "last-details-view-visible-columns", &tmp, NULL);
visible_columns = g_strsplit (tmp, ",", -1);
g_free (tmp);
/* reset the visible columns for the model */
for (n = 0; n < THUNAR_N_VISIBLE_COLUMNS; ++n)
column_model->visible[n] = FALSE;
/* mark all columns included in the list as visible */
klass = g_type_class_ref (THUNAR_TYPE_COLUMN);
for (n = 0; visible_columns[n] != NULL; ++n)
{
/* determine the enum value from the string */
value = g_enum_get_value_by_name (klass, visible_columns[n]);
if (G_LIKELY (value != NULL && value->value < THUNAR_N_VISIBLE_COLUMNS))
column_model->visible[value->value] = TRUE;
}
g_type_class_unref (klass);
/* the name column is always visible */
column_model->visible[THUNAR_COLUMN_NAME] = TRUE;
/* release the list of visible columns */
g_strfreev (visible_columns);
}
static void
thunar_column_model_save_visible_columns (ThunarColumnModel *column_model)
{
GEnumClass *klass;
GString *visible_columns;
gint n;
/* allocate a string for the visible columns list */
visible_columns = g_string_sized_new (128);
/* transform the internal visible column list */
klass = g_type_class_ref (THUNAR_TYPE_COLUMN);
for (n = 0; n < THUNAR_N_VISIBLE_COLUMNS; ++n)
if (column_model->visible[klass->values[n].value])
{
/* skip special columns */
if (thunar_column_is_special (klass->values[n].value))
continue;
/* append a comma if not empty */
if (*visible_columns->str != '\0')
g_string_append_c (visible_columns, ',');
/* append the enum value name */
g_string_append (visible_columns, klass->values[n].value_name);
}
g_type_class_unref (klass);
/* save the list of visible columns */
g_signal_handlers_block_by_func (G_OBJECT (column_model->preferences), thunar_column_model_notify_visible_columns, column_model);
g_object_set (G_OBJECT (column_model->preferences), "last-details-view-visible-columns", visible_columns->str, NULL);
g_signal_handlers_unblock_by_func (G_OBJECT (column_model->preferences), thunar_column_model_notify_visible_columns, column_model);
/* release the string */
g_string_free (visible_columns, TRUE);
}
static void
thunar_column_model_notify_visible_columns (ThunarPreferences *preferences,
GParamSpec *pspec,
ThunarColumnModel *column_model)
{
GtkTreePath *path;
GtkTreeIter iter;
gint n;
_thunar_return_if_fail (THUNAR_IS_COLUMN_MODEL (column_model));
_thunar_return_if_fail (THUNAR_IS_PREFERENCES (preferences));
/* load the new list of visible columns */
thunar_column_model_load_visible_columns (column_model);
/* emit "row-changed" for all rows */
for (n = 0; n < THUNAR_N_VISIBLE_COLUMNS; ++n)
{
path = gtk_tree_path_new_from_indices (n, -1);
if (gtk_tree_model_get_iter (GTK_TREE_MODEL (column_model), &iter, path))
gtk_tree_model_row_changed (GTK_TREE_MODEL (column_model), path, &iter);
gtk_tree_path_free (path);
}
/* emit "columns-changed" */
g_signal_emit (G_OBJECT (column_model), column_model_signals[COLUMNS_CHANGED], 0);
}
static gboolean
thunar_column_model_set_column_width_timer (gpointer user_data)
{
ThunarColumnModel *column_model = THUNAR_COLUMN_MODEL (user_data);
thunar_column_model_save_column_widths (column_model);
column_model->save_width_timer_id = 0;
return FALSE;
}
/**
* thunar_column_model_get_default:
*
* Returns the default, shared #ThunarColumnModel
* instance.
*
* The caller is responsible to free the returned
* object using g_object_unref() when no longer
* needed.
*
* Return value: the default #ThunarColumnModel.
**/
ThunarColumnModel *
thunar_column_model_get_default (void)
{
static ThunarColumnModel *column_model = NULL;
if (G_UNLIKELY (column_model == NULL))
{
column_model = g_object_new (THUNAR_TYPE_COLUMN_MODEL, NULL);
g_object_add_weak_pointer (G_OBJECT (column_model), (gpointer) &column_model);
}
else
{
g_object_ref (G_OBJECT (column_model));
}
return column_model;
}
/**
* thunar_column_model_exchange:
* @column_model : a #ThunarColumnModel.
* @iter1 : first #GtkTreeIter.
* @iter2 : second #GtkTreeIter.
*
* Exchanges the columns at @iter1 and @iter2
* in @column_model.
**/
void
thunar_column_model_exchange (ThunarColumnModel *column_model,
GtkTreeIter *iter1,
GtkTreeIter *iter2)
{
ThunarColumn column;
GtkTreePath *path;
gint new_order[THUNAR_N_VISIBLE_COLUMNS];
gint n;
_thunar_return_if_fail (THUNAR_IS_COLUMN_MODEL (column_model));
_thunar_return_if_fail (iter1->stamp == column_model->stamp);
_thunar_return_if_fail (iter2->stamp == column_model->stamp);
/* swap the columns */
column = column_model->order[GPOINTER_TO_INT (iter1->user_data)];
column_model->order[GPOINTER_TO_INT (iter1->user_data)] = column_model->order[GPOINTER_TO_INT (iter2->user_data)];
column_model->order[GPOINTER_TO_INT (iter2->user_data)] = column;
/* initialize the new order array */
for (n = 0; n < THUNAR_N_VISIBLE_COLUMNS; ++n)
new_order[n] = n;
/* perform the swapping on the new order array */
new_order[GPOINTER_TO_INT (iter1->user_data)] = GPOINTER_TO_INT (iter2->user_data);
new_order[GPOINTER_TO_INT (iter2->user_data)] = GPOINTER_TO_INT (iter1->user_data);
/* emit "rows-reordered" */
path = gtk_tree_path_new ();
gtk_tree_model_rows_reordered (GTK_TREE_MODEL (column_model), path, NULL, new_order);
gtk_tree_path_free (path);
/* emit "columns-changed" */
g_signal_emit (G_OBJECT (column_model), column_model_signals[COLUMNS_CHANGED], 0);
/* save the new column order */
thunar_column_model_save_column_order (column_model);
}
/**
* thunar_column_model_get_column_for_iter:
* @column_model : a #ThunarColumnModel.
* @iter : a valid #GtkTreeIter for @column_model.
*
* Returns the #ThunarColumn for the given @iter in
* @column_model.
*
* Return value: the #ThunarColumn for @iter.
**/
ThunarColumn
thunar_column_model_get_column_for_iter (ThunarColumnModel *column_model,
GtkTreeIter *iter)
{
_thunar_return_val_if_fail (THUNAR_IS_COLUMN_MODEL (column_model), -1);
_thunar_return_val_if_fail (iter->stamp == column_model->stamp, -1);
return column_model->order[GPOINTER_TO_INT (iter->user_data)];
}
/**
* thunar_column_model_get_column_order:
* @column_model : a #ThunarColumnModel.
*
* Returns the current #ThunarColumn order for @column_model.
*
* Return value: the current #ThunarColumn order for the given
* @column_model instance.
**/
const ThunarColumn *
thunar_column_model_get_column_order (ThunarColumnModel *column_model)
{
_thunar_return_val_if_fail (THUNAR_IS_COLUMN_MODEL (column_model), NULL);
return column_model->order;
}
/**
* thunar_column_model_get_column_name:
* @column_model : a #ThunarColumnModel.
* @column : a #ThunarColumn.
*
* Returns the user visible name for the @column in
* the @column_model.
*
* Return value: the user visible name for @column.
**/
const gchar *
thunar_column_model_get_column_name (ThunarColumnModel *column_model,
ThunarColumn column)
{
const gchar *column_name = _("Unknown");
GEnumClass *klass;
guint n;
_thunar_return_val_if_fail (THUNAR_IS_COLUMN_MODEL (column_model), NULL);
_thunar_return_val_if_fail (column < THUNAR_N_VISIBLE_COLUMNS, NULL);
/* determine the column name from the ThunarColumn enum type */
klass = g_type_class_ref (THUNAR_TYPE_COLUMN);
for (n = 0; n < klass->n_values; ++n)
if (klass->values[n].value == (gint) column)
column_name = _(klass->values[n].value_nick);
g_type_class_unref (klass);
return column_name;
}
/**
* thunar_column_model_get_column_visible:
* @column_model : a #ThunarColumnModel.
* @column : a #ThunarColumn.
*
* Returns %TRUE if the @column should be displayed
* in the details view.
*
* Return value: %TRUE if @column is visible.
**/
gboolean
thunar_column_model_get_column_visible (ThunarColumnModel *column_model,
ThunarColumn column)
{
_thunar_return_val_if_fail (THUNAR_IS_COLUMN_MODEL (column_model), FALSE);
_thunar_return_val_if_fail (column < THUNAR_N_VISIBLE_COLUMNS, FALSE);
return column_model->visible[column];
}
/**
* thunar_column_model_set_column_visible:
* @column_model : a #ThunarColumnModel.
* @column : a #ThunarColumn.
* @visible : %TRUE to make @column visible.
*
* Changes the visibility of the @column to @visible in
* @column_model.
**/
void
thunar_column_model_set_column_visible (ThunarColumnModel *column_model,
ThunarColumn column,
gboolean visible)
{
ThunarColumn column_real = 0;
GtkTreePath *path;
GtkTreeIter iter;
gint n;
_thunar_return_if_fail (THUNAR_IS_COLUMN_MODEL (column_model));
_thunar_return_if_fail (column < THUNAR_N_VISIBLE_COLUMNS);
/* cannot change the visibility of the name column */
if (G_UNLIKELY (column == THUNAR_COLUMN_NAME))
return;
/* normalize the value */
visible = !!visible;
/* check if we have a new value */
if (G_LIKELY (column_model->visible[column] != visible) || thunar_column_is_special (column))
{
/* apply the new value */
column_model->visible[column] = visible;
/* reverse lookup the real column */
for (n = 0; n < THUNAR_N_VISIBLE_COLUMNS; ++n)
if (column_model->order[n] == column)
{
column_real = n;
break;
}
/* emit "row-changed" */
path = gtk_tree_path_new_from_indices (column_real, -1);
if (gtk_tree_model_get_iter (GTK_TREE_MODEL (column_model), &iter, path))
gtk_tree_model_row_changed (GTK_TREE_MODEL (column_model), path, &iter);
gtk_tree_path_free (path);
/* emit "columns-changed" */
g_signal_emit (G_OBJECT (column_model), column_model_signals[COLUMNS_CHANGED], 0);
/* save the list of visible columns (excluding special columns) */
if (!thunar_column_is_special (column))
thunar_column_model_save_visible_columns (column_model);
}
}
/**
* thunar_column_model_get_column_width:
* @column_model : a #ThunarColumnModel.
* @column : a #ThunarColumn.
*
* Returns the fixed column width for @column in
* @column_model.
*
* Return value: the fixed width for @column.
**/
gint
thunar_column_model_get_column_width (ThunarColumnModel *column_model,
ThunarColumn column)
{
_thunar_return_val_if_fail (THUNAR_IS_COLUMN_MODEL (column_model), -1);
_thunar_return_val_if_fail (column < THUNAR_N_VISIBLE_COLUMNS, -1);
return column_model->width[column];
}
/**
* thunar_column_model_set_column_width:
* @column_model : a #ThunarColumnModel.
* @column : a #ThunarColumn.
* @width : the new fixed width for @column.
*
* Sets the fixed width for @column in @column_model
* to @width.
**/
void
thunar_column_model_set_column_width (ThunarColumnModel *column_model,
ThunarColumn column,
gint width)
{
_thunar_return_if_fail (THUNAR_IS_COLUMN_MODEL (column_model));
_thunar_return_if_fail (column < THUNAR_N_VISIBLE_COLUMNS);
_thunar_return_if_fail (width >= 0);
/* check if we have a new width */
if (G_LIKELY (column_model->width[column] != width))
{
/* apply the new value */
column_model->width[column] = width;
/* store the settings... */
if (column_model->save_width_timer_id != 0)
{
g_source_remove (column_model->save_width_timer_id);
column_model->save_width_timer_id = 0;
}
/* ... asynchronously and only once to not overload xfconf */
column_model->save_width_timer_id = g_timeout_add (1000,
thunar_column_model_set_column_width_timer,
column_model);
}
}