355 lines
9.4 KiB
C
355 lines
9.4 KiB
C
|
/*
|
||
|
* Copyright (C) 2012 - Juan Ferrer Toribio
|
||
|
*
|
||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#include "vn-grid.h"
|
||
|
|
||
|
G_DEFINE_TYPE (VnGrid, vn_grid, GTK_TYPE_TREE_VIEW);
|
||
|
|
||
|
/**
|
||
|
* vn_grid_new:
|
||
|
*
|
||
|
* Creates a new grid
|
||
|
*
|
||
|
* Return value: #VnGrid created.
|
||
|
**/
|
||
|
VnGrid * vn_grid_new ()
|
||
|
{
|
||
|
return g_object_new (VN_TYPE_GRID, "rules-hint", TRUE, NULL);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* vn_grid_new_with_iterator:
|
||
|
* @iterator: #DbIterator where the grid will be created
|
||
|
*
|
||
|
* Creates a new grid into a iterator
|
||
|
*
|
||
|
* Return value: #VnGrid created.
|
||
|
**/
|
||
|
VnGrid * vn_grid_new_with_iterator (DbIterator * iterator)
|
||
|
{
|
||
|
VnGrid * obj = vn_grid_new ();
|
||
|
g_object_set (obj, "iterator", iterator, NULL);
|
||
|
return obj;
|
||
|
}
|
||
|
|
||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Private
|
||
|
|
||
|
static void vn_grid_on_iter_changed (DbIterator * iterator, GtkTreeView * obj);
|
||
|
|
||
|
static void vn_grid_on_cursor_changed (GtkTreeView * obj, DbIterator * iterator)
|
||
|
{
|
||
|
GtkTreeIter iter;
|
||
|
GtkTreeSelection * selection = gtk_tree_view_get_selection (obj);
|
||
|
|
||
|
if (selection && gtk_tree_selection_get_selected (selection, NULL, &iter))
|
||
|
{
|
||
|
DbIter dbiter;
|
||
|
vn_gtk_tree_iter_to_db_iter (&iter, &dbiter);
|
||
|
|
||
|
g_signal_handlers_block_by_func (iterator, vn_grid_on_iter_changed, obj);
|
||
|
db_iterator_move_iter (iterator, &dbiter);
|
||
|
g_signal_handlers_unblock_by_func (iterator, vn_grid_on_iter_changed, obj);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void vn_grid_on_iter_changed (DbIterator * iterator, GtkTreeView * obj)
|
||
|
{
|
||
|
DbIter dbiter;
|
||
|
GtkTreeSelection * selection = gtk_tree_view_get_selection (obj);
|
||
|
|
||
|
if (db_iterator_get_iter (iterator, &dbiter)
|
||
|
&& gtk_tree_view_get_model (obj))
|
||
|
{
|
||
|
GtkTreeIter iter;
|
||
|
GtkTreePath * path;
|
||
|
|
||
|
vn_gtk_tree_iter_from_db_iter (&iter, &dbiter);
|
||
|
g_signal_handlers_block_by_func (obj, vn_grid_on_cursor_changed, iterator);
|
||
|
gtk_tree_selection_select_iter (selection, &iter);
|
||
|
g_signal_handlers_unblock_by_func (obj, vn_grid_on_cursor_changed, iterator);
|
||
|
|
||
|
path = gtk_tree_model_get_path (
|
||
|
gtk_tree_view_get_model (obj), &iter);
|
||
|
gtk_tree_view_scroll_to_cell (obj, path, NULL, FALSE, 0, 0);
|
||
|
gtk_tree_path_free (path);
|
||
|
}
|
||
|
else if (selection)
|
||
|
gtk_tree_selection_unselect_all (selection);
|
||
|
}
|
||
|
|
||
|
static void vn_grid_on_status_changed (DbIterator * iterator, gboolean ready, VnGrid * obj)
|
||
|
{
|
||
|
GList * n;
|
||
|
GList * columns;
|
||
|
|
||
|
obj->model = db_iterator_get_model (iterator);
|
||
|
columns = gtk_tree_view_get_columns (GTK_TREE_VIEW (obj));
|
||
|
|
||
|
for (n = columns; n; n = n->next)
|
||
|
if (VN_IS_COLUMN (n->data))
|
||
|
vn_column_model_changed (n->data);
|
||
|
|
||
|
g_list_free (columns);
|
||
|
|
||
|
if (ready)
|
||
|
{
|
||
|
GtkTreeModel * tree_model = GTK_TREE_MODEL (vn_model_new (obj->model));
|
||
|
gtk_tree_view_set_model (GTK_TREE_VIEW (obj), tree_model);
|
||
|
vn_grid_on_iter_changed (obj->iterator, GTK_TREE_VIEW (obj));
|
||
|
g_object_unref (tree_model);
|
||
|
}
|
||
|
else
|
||
|
gtk_tree_view_set_model (GTK_TREE_VIEW (obj), NULL);
|
||
|
}
|
||
|
|
||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Public
|
||
|
|
||
|
/**
|
||
|
* vn_grid_get_iterator:
|
||
|
* @obj: a #VnGrid
|
||
|
*
|
||
|
* Gets the iterator used by @obj.
|
||
|
*
|
||
|
* Return value: (transfer none): the #DbIterator
|
||
|
**/
|
||
|
DbIterator * vn_grid_get_iterator (VnGrid * obj)
|
||
|
{
|
||
|
g_return_val_if_fail (VN_IS_GRID (obj), NULL);
|
||
|
|
||
|
return obj->iterator;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* vn_grid_set_iterator:
|
||
|
* @obj: a #VnGrid
|
||
|
* @iterator: the #DbIterator
|
||
|
*
|
||
|
* Sets the iterator handled by tree view.
|
||
|
**/
|
||
|
void vn_grid_set_iterator (VnGrid * obj, DbIterator * iterator)
|
||
|
{
|
||
|
g_return_if_fail (VN_IS_GRID (obj));
|
||
|
g_return_if_fail (DB_IS_ITERATOR (iterator) || !iterator);
|
||
|
|
||
|
if (obj->iterator)
|
||
|
{
|
||
|
g_signal_handlers_disconnect_by_func (obj,
|
||
|
vn_grid_on_cursor_changed, obj->iterator);
|
||
|
|
||
|
g_object_disconnect (obj->iterator
|
||
|
,"any-signal", vn_grid_on_iter_changed, obj
|
||
|
,"any-signal", vn_grid_on_status_changed, obj
|
||
|
,NULL
|
||
|
);
|
||
|
g_clear_object (&obj->iterator);
|
||
|
obj->model = NULL;
|
||
|
}
|
||
|
if (iterator)
|
||
|
{
|
||
|
obj->iterator = g_object_ref (iterator);
|
||
|
g_object_connect (iterator
|
||
|
,"signal::iter-changed", vn_grid_on_iter_changed, obj
|
||
|
,"signal::status-changed", vn_grid_on_status_changed, obj
|
||
|
,NULL
|
||
|
);
|
||
|
vn_grid_on_status_changed (iterator,
|
||
|
db_iterator_is_ready (iterator), obj);
|
||
|
|
||
|
g_signal_connect (obj, "cursor-changed",
|
||
|
G_CALLBACK (vn_grid_on_cursor_changed), iterator);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* vn_grid_get_model:
|
||
|
* @obj: a #VnGrid
|
||
|
*
|
||
|
* Gets the model used by @obj.
|
||
|
*
|
||
|
* Return value: (transfer none): the #DbModel
|
||
|
**/
|
||
|
DbModel * vn_grid_get_model (VnGrid * obj)
|
||
|
{
|
||
|
g_return_val_if_fail (VN_IS_GRID (obj), NULL);
|
||
|
|
||
|
return obj->model;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* vn_grid_insert_column:
|
||
|
* @obj: #VnGrid where the new column will be appended
|
||
|
* @position: the position where the column will be inserted
|
||
|
* @column_index: the index of the source column in the model
|
||
|
* @title: the title
|
||
|
* @column_type: the #GType of the assigned #VnColumn
|
||
|
* @editable: a %gboolean indicating whether the column is editable
|
||
|
* @expand: a %gboolean indicating whether the column is expandable
|
||
|
*
|
||
|
* Creates and inserts a new column in the grid with the given column and
|
||
|
* position, if @position is -1 the column will be appended to the end.
|
||
|
*
|
||
|
* Return value: (transfer none): the #VnColumn assigned to the new column.
|
||
|
**/
|
||
|
VnColumn * vn_grid_insert_column (VnGrid * obj, gint position, gint column_index,
|
||
|
const gchar * title, GType column_type, gboolean editable, gboolean expand)
|
||
|
{
|
||
|
GtkTreeViewColumn * column;
|
||
|
|
||
|
g_return_val_if_fail (VN_IS_GRID (obj), NULL);
|
||
|
g_return_val_if_fail (index >= 0, NULL);
|
||
|
g_return_val_if_fail (g_type_is_a (column_type, VN_TYPE_COLUMN), NULL);
|
||
|
|
||
|
column = g_object_new (column_type
|
||
|
,"title" ,title
|
||
|
,"expand" ,expand
|
||
|
,"resizable" ,TRUE
|
||
|
,"sort-indicator" ,TRUE
|
||
|
,"sizing" ,GTK_TREE_VIEW_COLUMN_GROW_ONLY
|
||
|
,"column-index" ,column_index
|
||
|
,"editable" ,editable
|
||
|
,NULL
|
||
|
);
|
||
|
gtk_tree_view_append_column (GTK_TREE_VIEW (obj), column);
|
||
|
return VN_COLUMN (column);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* vn_grid_append_column:
|
||
|
* @obj: #VnGrid where the new column will be appended
|
||
|
* @column_index: the index of the source column in the model
|
||
|
* @title: the title
|
||
|
* @column_type: the #GType of the assigned #VnCell
|
||
|
* @editable: a %gboolean indicating whether the column is editable
|
||
|
* @expand: a %gboolean indicating whether the column is expandable
|
||
|
*
|
||
|
* Creates and appends a new column at the end of the grid with the given column.
|
||
|
*
|
||
|
* Return value: (transfer none): the #VnCell assigned to the new column.
|
||
|
**/
|
||
|
VnColumn * vn_grid_append_column (VnGrid * obj, gint column_index, const gchar * title,
|
||
|
GType column_type, gboolean editable, gboolean expand)
|
||
|
{
|
||
|
g_return_val_if_fail (VN_IS_GRID (obj), NULL);
|
||
|
g_return_val_if_fail (index >= 0, NULL);
|
||
|
g_return_val_if_fail (g_type_is_a (column_type, VN_TYPE_COLUMN), NULL);
|
||
|
|
||
|
return vn_grid_insert_column (obj, -1, column_index, title, column_type, editable, expand);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* vn_grid_append_columns:
|
||
|
* @obj: the #VnGrid
|
||
|
* @...: columns information, see vn_grid_append_column(), terminated with -1
|
||
|
*
|
||
|
* Appends columns into a #VnGrid.
|
||
|
**/
|
||
|
void vn_grid_append_columns (VnGrid * obj, ...)
|
||
|
{
|
||
|
va_list vl;
|
||
|
gint index;
|
||
|
gchar * title;
|
||
|
GType column_type;
|
||
|
gboolean editable;
|
||
|
gboolean expand;
|
||
|
|
||
|
g_return_if_fail (VN_IS_GRID (obj));
|
||
|
|
||
|
va_start (vl, obj);
|
||
|
|
||
|
while ((index = va_arg (vl, gint)) != -1)
|
||
|
{
|
||
|
title = va_arg (vl, gchar *);
|
||
|
column_type = va_arg (vl, GType);
|
||
|
editable = va_arg (vl, gboolean);
|
||
|
expand = va_arg (vl, gboolean);
|
||
|
|
||
|
vn_grid_append_column (obj,
|
||
|
index, title, column_type, editable, expand);
|
||
|
}
|
||
|
|
||
|
va_end (vl);
|
||
|
gtk_tree_view_columns_autosize (GTK_TREE_VIEW (obj));
|
||
|
}
|
||
|
|
||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Properties
|
||
|
|
||
|
typedef enum
|
||
|
{
|
||
|
PROP_ITERATOR = 1
|
||
|
}
|
||
|
VnGridProp;
|
||
|
|
||
|
static void vn_grid_set_property (VnGrid * obj, guint id,
|
||
|
const GValue * value, GParamSpec * pspec)
|
||
|
{
|
||
|
switch (id)
|
||
|
{
|
||
|
case PROP_ITERATOR:
|
||
|
vn_grid_set_iterator (obj, g_value_get_object (value));
|
||
|
break;
|
||
|
default:
|
||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void vn_grid_get_property (VnGrid * obj, guint id,
|
||
|
GValue * value, GParamSpec * pspec)
|
||
|
{
|
||
|
switch (id)
|
||
|
{
|
||
|
case PROP_ITERATOR:
|
||
|
g_value_set_object (value, obj->iterator);
|
||
|
break;
|
||
|
default:
|
||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Class
|
||
|
|
||
|
static void vn_grid_init (VnGrid * obj)
|
||
|
{
|
||
|
obj->iterator = NULL;
|
||
|
obj->model = NULL;
|
||
|
gtk_tree_selection_set_mode (
|
||
|
gtk_tree_view_get_selection (GTK_TREE_VIEW (obj)),
|
||
|
GTK_SELECTION_SINGLE
|
||
|
);
|
||
|
}
|
||
|
|
||
|
static void vn_grid_finalize (VnGrid * obj)
|
||
|
{
|
||
|
vn_grid_set_iterator (obj, NULL);
|
||
|
G_OBJECT_CLASS (vn_grid_parent_class)->finalize (G_OBJECT (obj));
|
||
|
}
|
||
|
|
||
|
static void vn_grid_class_init (VnGridClass * k)
|
||
|
{
|
||
|
GObjectClass * klass = G_OBJECT_CLASS (k);
|
||
|
klass->set_property = (GObjectSetPropertyFunc) vn_grid_set_property;
|
||
|
klass->get_property = (GObjectGetPropertyFunc) vn_grid_get_property;
|
||
|
klass->finalize = (GObjectFinalizeFunc) vn_grid_finalize;
|
||
|
|
||
|
g_object_class_install_property (klass, PROP_ITERATOR,
|
||
|
g_param_spec_object ("iterator"
|
||
|
,_("Iterator")
|
||
|
,_("The iterator used by VnGrid")
|
||
|
,DB_TYPE_ITERATOR
|
||
|
,G_PARAM_READWRITE
|
||
|
));
|
||
|
}
|