Files
evolution/widgets/table/e-tree.c
Tor Lillqvist 2decafb544 Port to Windows, initial commit:
2005-04-29  Tor Lillqvist  <tml@novell.com>

	Port to Windows, initial commit:

	* configure.in: Check for Win32, define Automake conditional
	OS_WIN32. Check for regexec() perhaps in separate -lregex, define
	REGEX_LIBS if so. Require glib-2.0 >= 2.6 (and thus also gtk+-2.0
	>= 2.6) so that we can use the gstdio wrappers for full support of
	non-ASCII filenames on Win32. Don't use -D_REENTRANT on Win32, has
	ne special meaning.

	* gal.pc.in: Require gtk+-2.0 >= 2.6 also here for consistency.

	* gal-zip.in: New file, used to build zipfile format distribution
	of gal for Win32.

	* configure.in
	* Makefile.am: Add gal-zip(.in).

	* */Makefile.am
	* */*.c: Harmonize -I and #include conventions. (Of course, this
	hasn't anything to do with Windows porting as such, I just got
	carried away...) Use only -I$(top_srcdir). Use paths to gal
	headers staring with "gal", except for headers from the same
	directory as the .c file, which are included as such. Include all
	gal headers using doublequotes. Sort #includes and remove
	duplicates and obvious redundancies. Include config.h first
	without any HAVE_CONFIG_H, then system headers, then other GNOME
	lib headers, than gal's own headers. Just include gtk.h instead of
	separate gtk*.h headers. Don't include gi18n.h, include e-i18n.h
	to use e_gettext() consistently.

	* gal/Makefile.am: Use -no-undefined on Win32 so that libtool
	agrees to build a shared library. Because of the bidirectional
	dependency between libgal and libgal-a11y we can build libgal-a11y
	sanely as a shared library on Win32, so we don't install any
	separate libgal-a11y at all. So, on Win32, link the stuff that
	goes into libgal-a11y also into libgal. Link with REGEX_LIBS.

	* gal/a11y/Makefile.am: See above. Just build a dummy static
	libgal-a11y on Win32 (can't convince Automake not to build the
	library at all on one platform using Automake ifdef,
	apparently). Then (this is a gross hack) explicitly remove the
	library after installation in the install-data-local rule.

	* gal/e-table/Makefile.am
	* gal/e-table/e-table-config.c: Rename ETABLE_GLADEDIR to
	GAL_GLADEDIR for consistency.

	* gal/e-table/e-cell-date.c: No localtime_r() in Microsoft's C
	library, but its localtime() *is* thread-safe.

	* gal/e-table/e-cell-text.c
	* gal/e-table/e-cell-tree.c
	* gal/e-table/e-cell-vbox.c
	* gal/e-text/e-text.c
	* gal/widgets/e-unicode.c: Remove unnecessary inclusion of gdkx.h.

	* gal/e-table/e-cell-tree.c (ect_realize): Instead of the Xlib
	macro None (whose value is zero), use the corresponding
	zero-valued enums from the appropriate GDK type.

	* gal/e-table/e-table-config.c
	* gal/e-table/e-table-field-chooser.c
	* gal/menus/gal-define-views-dialog.c
	* gal/menus/gal-view-instance-save-as-dialog.c
	* gal/menus/gal-view-new-dialog.c
	* gal/widgets/e-categories-master-list-array.c
	* gal/widgets/e-categories-master-list-dialog.c
	* gal/widgets/e-categories.c: Use g_build_filename() to construct
	pathnames at run-time instead of compile-time. On Windows the
	macros GAL_GLADEDIR and GAL_IMAGESDIR expand to function calls, in
	order to support installing in a freely chosen location.

	* gal/e-table/e-table-item.c
	* gal/e-table/e-cell-vbox.c: Instrad of the Xlib GrabSuccess, use
	GDK_GRAB_SUCCESS (which has the same value).

	* gal/e-table/e-table-specification.c (e_table_specification_load_from_file)
	* gal/e-table/e-table.c (e_table_load_specification)
	* gal/e-table/e-tree-table-adapter.c (open_file)
	* gal/menus/gal-view-instance.c (load_current_view)
	* gal/menus/gal-view-instance.c (load_current_view): On Win32,
	convert filename to the locale character set before passing to
	xmlParseFile() which doesn't use UTF-8 filenames. Use gstdio
	wrappers.

	* gal/util/Makefile.am: Define GAL_PREFIX as $prefix. Define
	GAL_LOCALEDIR, GAL_GLADEDIR and GAL_IMAGESDIR also here for
	e-win32-reloc.c. Include e-win32-reloc.c on Win32.

	* gal/util/e-iconv.c (e_iconv_init): Use g_win32_getlocale() on
	Windows.

	* gal/util/e-util.c
	* gal/util/e-xml-utils.c: Use g_mkstemp() instead of non-portable
	mkstemp(). Use GLib pathname manipulation functions. Use gstdio
	wrappers.

	* gal/util/e-util-private.h: New file. Contains just Win32 bits
	for now that redefine the directory names from the Makefile as
	functions calls.

	* gal/util/e-win32-reloc.c: New file. Contains a minimal DllMain()
	and functions to support freely chosen installation location on
	Windows.

	* gal/util/e-xml-utils.c: No fsync() in the Microsoft C library.

	* gal/windgets/Makefile.am: Add -I$(top_srcdir)/gal for
	consistency with the sibling Makefile.am files.

	* gal/widgets/e-canvas.c: Instead of the Xlib AlreadyGrabbed, use
	GDK_GRAB_ALREADY_GRABBED.

svn path=/trunk/; revision=29249
2005-04-29 14:18:18 +00:00

3321 lines
87 KiB
C

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* e-tree.c
* Copyright 2000, 2001, Ximian, Inc.
*
* Authors:
* Chris Lahey <clahey@ximian.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License, version 2, as published by the Free Software Foundation.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
#include "gal/a11y/e-table/gal-a11y-e-tree.h"
#include "gal/util/e-i18n.h"
#include "gal/util/e-util.h"
#include "gal/util/e-marshal.h"
#include "gal/widgets/e-canvas.h"
#include "gal/widgets/e-canvas-background.h"
#include "e-table-column-specification.h"
#include "e-table-header-item.h"
#include "e-table-header.h"
#include "e-table-item.h"
#include "e-table-sort-info.h"
#include "e-table-utils.h"
#ifdef E_TREE_USE_TREE_SELECTION
#include "e-tree-selection-model.h"
#else
#include "e-table-selection-model.h"
#endif
#include "e-tree.h"
#include "e-tree-table-adapter.h"
#define COLUMN_HEADER_HEIGHT 16
#define PARENT_TYPE gtk_table_get_type ()
static GtkObjectClass *parent_class;
#define d(x)
#if d(!)0
#define e_table_item_leave_edit_(x) (e_table_item_leave_edit((x)), g_print ("%s: e_table_item_leave_edit\n", __FUNCTION__))
#else
#define e_table_item_leave_edit_(x) (e_table_item_leave_edit((x)))
#endif
enum {
CURSOR_CHANGE,
CURSOR_ACTIVATED,
SELECTION_CHANGE,
DOUBLE_CLICK,
RIGHT_CLICK,
CLICK,
KEY_PRESS,
START_DRAG,
STATE_CHANGE,
WHITE_SPACE_EVENT,
TREE_DRAG_BEGIN,
TREE_DRAG_END,
TREE_DRAG_DATA_GET,
TREE_DRAG_DATA_DELETE,
TREE_DRAG_LEAVE,
TREE_DRAG_MOTION,
TREE_DRAG_DROP,
TREE_DRAG_DATA_RECEIVED,
LAST_SIGNAL
};
enum {
PROP_0,
PROP_LENGTH_THRESHOLD,
PROP_HORIZONTAL_DRAW_GRID,
PROP_VERTICAL_DRAW_GRID,
PROP_DRAW_FOCUS,
PROP_ETTA,
PROP_UNIFORM_ROW_HEIGHT,
PROP_ALWAYS_SEARCH
};
enum {
ET_SCROLL_UP = 1 << 0,
ET_SCROLL_DOWN = 1 << 1,
ET_SCROLL_LEFT = 1 << 2,
ET_SCROLL_RIGHT = 1 << 3
};
struct ETreePriv {
ETreeModel *model;
ETreeTableAdapter *etta;
ETableHeader *full_header, *header;
guint structure_change_id, expansion_change_id;
ETableSortInfo *sort_info;
ESorter *sorter;
guint sort_info_change_id, group_info_change_id;
ESelectionModel *selection;
ETableSpecification *spec;
ETableSearch *search;
ETableCol *current_search_col;
guint search_search_id;
guint search_accept_id;
int reflow_idle_id;
int scroll_idle_id;
int hover_idle_id;
int table_model_change_id;
int table_row_change_id;
int table_cell_change_id;
GnomeCanvas *header_canvas, *table_canvas;
GnomeCanvasItem *header_item, *root;
GnomeCanvasItem *white_item;
GnomeCanvasItem *item;
gint length_threshold;
/*
* Configuration settings
*/
guint alternating_row_colors : 1;
guint horizontal_draw_grid : 1;
guint vertical_draw_grid : 1;
guint draw_focus : 1;
guint row_selection_active : 1;
guint horizontal_scrolling : 1;
guint scroll_direction : 4;
guint do_drag : 1;
guint uniform_row_height : 1;
guint search_col_set : 1;
guint always_search : 1;
ECursorMode cursor_mode;
int drop_row;
ETreePath drop_path;
int drop_col;
GnomeCanvasItem *drop_highlight;
int last_drop_x;
int last_drop_y;
int last_drop_time;
GdkDragContext *last_drop_context;
int hover_x;
int hover_y;
int drag_row;
ETreePath drag_path;
int drag_col;
ETreeDragSourceSite *site;
GList *expanded_list;
};
static guint et_signals [LAST_SIGNAL] = { 0, };
static void et_grab_focus (GtkWidget *widget);
static void et_drag_begin (GtkWidget *widget,
GdkDragContext *context,
ETree *et);
static void et_drag_end (GtkWidget *widget,
GdkDragContext *context,
ETree *et);
static void et_drag_data_get(GtkWidget *widget,
GdkDragContext *context,
GtkSelectionData *selection_data,
guint info,
guint time,
ETree *et);
static void et_drag_data_delete(GtkWidget *widget,
GdkDragContext *context,
ETree *et);
static void et_drag_leave(GtkWidget *widget,
GdkDragContext *context,
guint time,
ETree *et);
static gboolean et_drag_motion(GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
guint time,
ETree *et);
static gboolean et_drag_drop(GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
guint time,
ETree *et);
static void et_drag_data_received(GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
GtkSelectionData *selection_data,
guint info,
guint time,
ETree *et);
static void scroll_off (ETree *et);
static void scroll_on (ETree *et, guint scroll_direction);
static void hover_off (ETree *et);
static void hover_on (ETree *et, int x, int y);
static void context_destroyed (gpointer data, GObject *ctx);
static void
et_disconnect_from_etta (ETree *et)
{
if (et->priv->table_model_change_id != 0)
g_signal_handler_disconnect (G_OBJECT (et->priv->etta),
et->priv->table_model_change_id);
if (et->priv->table_row_change_id != 0)
g_signal_handler_disconnect (G_OBJECT (et->priv->etta),
et->priv->table_row_change_id);
if (et->priv->table_cell_change_id != 0)
g_signal_handler_disconnect (G_OBJECT (et->priv->etta),
et->priv->table_cell_change_id);
et->priv->table_model_change_id = 0;
et->priv->table_row_change_id = 0;
et->priv->table_cell_change_id = 0;
}
static void
clear_current_search_col (ETree *et)
{
et->priv->search_col_set = FALSE;
}
static ETableCol *
current_search_col (ETree *et)
{
if (!et->priv->search_col_set) {
et->priv->current_search_col =
e_table_util_calculate_current_search_col (et->priv->header,
et->priv->full_header,
et->priv->sort_info,
et->priv->always_search);
et->priv->search_col_set = TRUE;
}
return et->priv->current_search_col;
}
static void
e_tree_state_change (ETree *et)
{
g_signal_emit (G_OBJECT (et), et_signals [STATE_CHANGE], 0);
}
static void
change_trigger (GtkObject *object, ETree *et)
{
e_tree_state_change (et);
}
static void
search_col_change_trigger (GtkObject *object, ETree *et)
{
clear_current_search_col (et);
e_tree_state_change (et);
}
static void
disconnect_header (ETree *e_tree)
{
if (e_tree->priv->header == NULL)
return;
if (e_tree->priv->structure_change_id)
g_signal_handler_disconnect (G_OBJECT (e_tree->priv->header),
e_tree->priv->structure_change_id);
if (e_tree->priv->expansion_change_id)
g_signal_handler_disconnect (G_OBJECT (e_tree->priv->header),
e_tree->priv->expansion_change_id);
if (e_tree->priv->sort_info) {
if (e_tree->priv->sort_info_change_id)
g_signal_handler_disconnect (G_OBJECT (e_tree->priv->sort_info),
e_tree->priv->sort_info_change_id);
if (e_tree->priv->group_info_change_id)
g_signal_handler_disconnect (G_OBJECT (e_tree->priv->sort_info),
e_tree->priv->group_info_change_id);
g_object_unref(e_tree->priv->sort_info);
}
g_object_unref(e_tree->priv->header);
e_tree->priv->header = NULL;
e_tree->priv->sort_info = NULL;
}
static void
connect_header (ETree *e_tree, ETableState *state)
{
GValue *val = g_new0 (GValue, 1);
if (e_tree->priv->header != NULL)
disconnect_header (e_tree);
e_tree->priv->header = e_table_state_to_header (GTK_WIDGET(e_tree), e_tree->priv->full_header, state);
e_tree->priv->structure_change_id =
g_signal_connect (G_OBJECT (e_tree->priv->header), "structure_change",
G_CALLBACK (search_col_change_trigger), e_tree);
e_tree->priv->expansion_change_id =
g_signal_connect (G_OBJECT (e_tree->priv->header), "expansion_change",
G_CALLBACK (change_trigger), e_tree);
if (state->sort_info) {
e_tree->priv->sort_info = e_table_sort_info_duplicate(state->sort_info);
e_table_sort_info_set_can_group (e_tree->priv->sort_info, FALSE);
e_tree->priv->sort_info_change_id =
g_signal_connect (G_OBJECT (e_tree->priv->sort_info), "sort_info_changed",
G_CALLBACK (search_col_change_trigger), e_tree);
e_tree->priv->group_info_change_id =
g_signal_connect (G_OBJECT (e_tree->priv->sort_info), "group_info_changed",
G_CALLBACK (search_col_change_trigger), e_tree);
} else
e_tree->priv->sort_info = NULL;
g_value_init (val, G_TYPE_OBJECT);
g_value_set_object (val, e_tree->priv->sort_info);
g_object_set_property (G_OBJECT(e_tree->priv->header), "sort_info", val);
g_free (val);
}
static void
et_dispose (GObject *object)
{
ETree *et = E_TREE (object);
if (et->priv) {
if (et->priv->search) {
if (et->priv->search_search_id)
g_signal_handler_disconnect (et->priv->search,
et->priv->search_search_id);
if (et->priv->search_accept_id)
g_signal_handler_disconnect (et->priv->search,
et->priv->search_accept_id);
g_object_unref (et->priv->search);
}
if (et->priv->reflow_idle_id)
g_source_remove(et->priv->reflow_idle_id);
et->priv->reflow_idle_id = 0;
scroll_off (et);
hover_off (et);
e_free_string_list (et->priv->expanded_list);
et_disconnect_from_etta (et);
g_object_unref (et->priv->etta);
g_object_unref (et->priv->model);
g_object_unref (et->priv->full_header);
disconnect_header (et);
g_object_unref (et->priv->selection);
if (et->priv->spec)
g_object_unref (et->priv->spec);
et->priv->spec = NULL;
if (et->priv->sorter)
g_object_unref (et->priv->sorter);
et->priv->sorter = NULL;
if (et->priv->header_canvas)
gtk_widget_destroy (GTK_WIDGET (et->priv->header_canvas));
et->priv->header_canvas = NULL;
if (et->priv->site)
e_tree_drag_source_unset (et);
if (et->priv->last_drop_context)
g_object_weak_unref (G_OBJECT(et->priv->last_drop_context), context_destroyed, et);
et->priv->last_drop_context = NULL;
gtk_widget_destroy (GTK_WIDGET (et->priv->table_canvas));
g_free(et->priv);
et->priv = NULL;
}
if (G_OBJECT_CLASS (parent_class)->dispose)
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
et_unrealize (GtkWidget *widget)
{
scroll_off (E_TREE (widget));
hover_off (E_TREE (widget));
if (GTK_WIDGET_CLASS (parent_class)->unrealize)
GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
}
typedef struct {
ETree *et;
char *string;
} SearchSearchStruct;
static gboolean
search_search_callback (ETreeModel *model, ETreePath path, gpointer data)
{
SearchSearchStruct *cb_data = data;
const void *value;
ETableCol *col = current_search_col (cb_data->et);
value = e_tree_model_value_at (model, path, cb_data->et->priv->current_search_col->col_idx);
return col->search (value, cb_data->string);
}
static gboolean
et_search_search (ETableSearch *search, char *string, ETableSearchFlags flags, ETree *et)
{
ETreePath cursor;
ETreePath found;
SearchSearchStruct cb_data;
ETableCol *col = current_search_col (et);
if (col == NULL)
return FALSE;
cb_data.et = et;
cb_data.string = string;
cursor = e_tree_get_cursor (et);
if (cursor && (flags & E_TABLE_SEARCH_FLAGS_CHECK_CURSOR_FIRST)) {
const void *value;
value = e_tree_model_value_at (et->priv->model, cursor, col->col_idx);
if (col->search (value, string)) {
return TRUE;
}
}
found = e_tree_model_node_find (et->priv->model, cursor, NULL, E_TREE_FIND_NEXT_FORWARD, search_search_callback, &cb_data);
if (found == NULL)
found = e_tree_model_node_find (et->priv->model, NULL, cursor, E_TREE_FIND_NEXT_FORWARD, search_search_callback, &cb_data);
if (found && found != cursor) {
int model_row;
e_tree_table_adapter_show_node (et->priv->etta, found);
model_row = e_tree_table_adapter_row_of_node (et->priv->etta, found);
cursor = found;
e_selection_model_select_as_key_press(E_SELECTION_MODEL (et->priv->selection), model_row, col->col_idx, GDK_CONTROL_MASK);
return TRUE;
} else if (cursor && !(flags & E_TABLE_SEARCH_FLAGS_CHECK_CURSOR_FIRST)) {
const void *value;
value = e_tree_model_value_at (et->priv->model, cursor, col->col_idx);
return col->search (value, string);
} else
return FALSE;
}
static void
et_search_accept (ETableSearch *search, ETree *et)
{
ETableCol *col = current_search_col (et);
int cursor;
if (col == NULL)
return;
g_object_get(et->priv->selection,
"cursor_row", &cursor,
NULL);
e_selection_model_select_as_key_press(E_SELECTION_MODEL (et->priv->selection), cursor, col->col_idx, 0);
}
static void
e_tree_init (GtkObject *object)
{
ETree *e_tree = E_TREE (object);
GtkTable *gtk_table = GTK_TABLE (object);
GTK_WIDGET_SET_FLAGS (e_tree, GTK_CAN_FOCUS);
gtk_table->homogeneous = FALSE;
e_tree->priv = g_new(ETreePriv, 1);
e_tree->priv->model = NULL;
e_tree->priv->etta = NULL;
e_tree->priv->full_header = NULL;
e_tree->priv->header = NULL;
e_tree->priv->structure_change_id = 0;
e_tree->priv->expansion_change_id = 0;
e_tree->priv->sort_info_change_id = 0;
e_tree->priv->group_info_change_id = 0;
e_tree->priv->sort_info = NULL;
e_tree->priv->sorter = NULL;
e_tree->priv->reflow_idle_id = 0;
e_tree->priv->scroll_idle_id = 0;
e_tree->priv->hover_idle_id = 0;
e_tree->priv->table_model_change_id = 0;
e_tree->priv->table_row_change_id = 0;
e_tree->priv->table_cell_change_id = 0;
e_tree->priv->alternating_row_colors = 1;
e_tree->priv->horizontal_draw_grid = 1;
e_tree->priv->vertical_draw_grid = 1;
e_tree->priv->draw_focus = 1;
e_tree->priv->cursor_mode = E_CURSOR_SIMPLE;
e_tree->priv->length_threshold = 200;
e_tree->priv->uniform_row_height = FALSE;
e_tree->priv->row_selection_active = FALSE;
e_tree->priv->horizontal_scrolling = FALSE;
e_tree->priv->scroll_direction = 0;
e_tree->priv->drop_row = -1;
e_tree->priv->drop_path = NULL;
e_tree->priv->drop_col = -1;
e_tree->priv->drop_highlight = NULL;
e_tree->priv->last_drop_x = 0;
e_tree->priv->last_drop_y = 0;
e_tree->priv->last_drop_time = 0;
e_tree->priv->last_drop_context = NULL;
e_tree->priv->hover_x = 0;
e_tree->priv->hover_y = 0;
e_tree->priv->drag_row = -1;
e_tree->priv->drag_path = NULL;
e_tree->priv->drag_col = -1;
e_tree->priv->expanded_list = NULL;
e_tree->priv->site = NULL;
e_tree->priv->do_drag = FALSE;
#ifdef E_TREE_USE_TREE_SELECTION
e_tree->priv->selection = E_SELECTION_MODEL(e_tree_selection_model_new());
#else
e_tree->priv->selection = E_SELECTION_MODEL(e_table_selection_model_new());
#endif
e_tree->priv->spec = NULL;
e_tree->priv->header_canvas = NULL;
e_tree->priv->table_canvas = NULL;
e_tree->priv->header_item = NULL;
e_tree->priv->root = NULL;
e_tree->priv->white_item = NULL;
e_tree->priv->item = NULL;
e_tree->priv->search = e_table_search_new();
e_tree->priv->search_search_id =
g_signal_connect (G_OBJECT (e_tree->priv->search), "search",
G_CALLBACK (et_search_search), e_tree);
e_tree->priv->search_accept_id =
g_signal_connect (G_OBJECT (e_tree->priv->search), "accept",
G_CALLBACK (et_search_accept), e_tree);
e_tree->priv->current_search_col = NULL;
e_tree->priv->search_col_set = FALSE;
e_tree->priv->always_search = g_getenv ("GAL_ALWAYS_SEARCH") ? TRUE : FALSE;
}
/* Grab_focus handler for the ETree */
static void
et_grab_focus (GtkWidget *widget)
{
ETree *e_tree;
e_tree = E_TREE (widget);
gtk_widget_grab_focus (GTK_WIDGET (e_tree->priv->table_canvas));
}
/* Focus handler for the ETree */
static gint
et_focus (GtkWidget *container, GtkDirectionType direction)
{
ETree *e_tree;
e_tree = E_TREE (container);
if (GTK_CONTAINER (container)->focus_child) {
gtk_container_set_focus_child (GTK_CONTAINER (container), NULL);
return FALSE;
}
return gtk_widget_child_focus (GTK_WIDGET (e_tree->priv->table_canvas), direction);
}
static void
set_header_canvas_width (ETree *e_tree)
{
double oldwidth, oldheight, width;
if (!(e_tree->priv->header_item && e_tree->priv->header_canvas && e_tree->priv->table_canvas))
return;
gnome_canvas_get_scroll_region (GNOME_CANVAS (e_tree->priv->table_canvas),
NULL, NULL, &width, NULL);
gnome_canvas_get_scroll_region (GNOME_CANVAS (e_tree->priv->header_canvas),
NULL, NULL, &oldwidth, &oldheight);
if (oldwidth != width ||
oldheight != E_TABLE_HEADER_ITEM (e_tree->priv->header_item)->height - 1)
gnome_canvas_set_scroll_region (
GNOME_CANVAS (e_tree->priv->header_canvas),
0, 0, width, /* COLUMN_HEADER_HEIGHT - 1 */
E_TABLE_HEADER_ITEM (e_tree->priv->header_item)->height - 1);
}
static void
header_canvas_size_allocate (GtkWidget *widget, GtkAllocation *alloc, ETree *e_tree)
{
set_header_canvas_width (e_tree);
/* When the header item is created ->height == 0,
as the font is only created when everything is realized.
So we set the usize here as well, so that the size of the
header is correct */
if (GTK_WIDGET (e_tree->priv->header_canvas)->allocation.height !=
E_TABLE_HEADER_ITEM (e_tree->priv->header_item)->height)
gtk_widget_set_usize (GTK_WIDGET (e_tree->priv->header_canvas), -1,
E_TABLE_HEADER_ITEM (e_tree->priv->header_item)->height);
}
static void
e_tree_setup_header (ETree *e_tree)
{
char *pointer;
e_tree->priv->header_canvas = GNOME_CANVAS (e_canvas_new ());
GTK_WIDGET_UNSET_FLAGS (e_tree->priv->header_canvas, GTK_CAN_FOCUS);
gtk_widget_show (GTK_WIDGET (e_tree->priv->header_canvas));
pointer = g_strdup_printf("%p", e_tree);
e_tree->priv->header_item = gnome_canvas_item_new (
gnome_canvas_root (e_tree->priv->header_canvas),
e_table_header_item_get_type (),
"ETableHeader", e_tree->priv->header,
"full_header", e_tree->priv->full_header,
"sort_info", e_tree->priv->sort_info,
"dnd_code", pointer,
"tree", e_tree,
NULL);
g_free(pointer);
g_signal_connect (
e_tree->priv->header_canvas, "size_allocate",
G_CALLBACK (header_canvas_size_allocate), e_tree);
gtk_widget_set_usize (GTK_WIDGET (e_tree->priv->header_canvas), -1,
E_TABLE_HEADER_ITEM (e_tree->priv->header_item)->height);
}
static gboolean
tree_canvas_reflow_idle (ETree *e_tree)
{
gdouble height, width;
gdouble item_height;
gdouble oldheight, oldwidth;
GtkAllocation *alloc = &(GTK_WIDGET (e_tree->priv->table_canvas)->allocation);
g_object_get (e_tree->priv->item,
"height", &height,
"width", &width,
NULL);
item_height = height;
height = MAX ((int)height, alloc->height);
width = MAX((int)width, alloc->width);
/* I have no idea why this needs to be -1, but it works. */
gnome_canvas_get_scroll_region (GNOME_CANVAS (e_tree->priv->table_canvas),
NULL, NULL, &oldwidth, &oldheight);
if (oldwidth != width - 1 ||
oldheight != height - 1) {
gnome_canvas_set_scroll_region (GNOME_CANVAS (e_tree->priv->table_canvas),
0, 0, width - 1, height - 1);
set_header_canvas_width (e_tree);
}
e_tree->priv->reflow_idle_id = 0;
return FALSE;
}
static void
tree_canvas_size_allocate (GtkWidget *widget, GtkAllocation *alloc,
ETree *e_tree)
{
gdouble width;
gdouble height;
gdouble item_height;
GtkAdjustment *adj = GTK_LAYOUT(e_tree->priv->table_canvas)->vadjustment;
ETreePath path = e_tree_get_cursor (e_tree);
gint x, y, w, h;
GValue *val = g_new0 (GValue, 1);
g_value_init (val, G_TYPE_DOUBLE);
width = alloc->width;
g_value_set_double (val, width);
g_object_get (e_tree->priv->item,
"height", &height,
NULL);
item_height = height;
height = MAX ((int)height, alloc->height);
g_object_set (e_tree->priv->item,
"width", width,
NULL);
g_object_set_property (G_OBJECT (e_tree->priv->header), "width", val);
g_free (val);
if (e_tree->priv->reflow_idle_id)
g_source_remove(e_tree->priv->reflow_idle_id);
tree_canvas_reflow_idle(e_tree);
x = y = w = h = 0;
if (path) {
int row = e_tree_row_of_node(e_tree, path);
int col = 0;
if (row >= 0)
e_table_item_get_cell_geometry (E_TABLE_ITEM (e_tree->priv->item),
&row, &col, &x, &y, &w, &h);
}
if (y < adj->value || y + h > adj->value + adj->page_size)
gtk_adjustment_set_value(adj, CLAMP(y - adj->page_size / 2, adj->lower, adj->upper - adj->page_size));
}
static void
tree_canvas_reflow (GnomeCanvas *canvas, ETree *e_tree)
{
if (!e_tree->priv->reflow_idle_id)
e_tree->priv->reflow_idle_id = g_idle_add_full (400, (GSourceFunc) tree_canvas_reflow_idle, e_tree, NULL);
}
static void
item_cursor_change (ETableItem *eti, int row, ETree *et)
{
ETreePath path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
g_signal_emit (et,
et_signals [CURSOR_CHANGE], 0,
row, path);
}
static void
item_cursor_activated (ETableItem *eti, int row, ETree *et)
{
ETreePath path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
g_signal_emit (et,
et_signals [CURSOR_ACTIVATED], 0,
row, path);
d(g_print("%s: Emitted CURSOR_ACTIVATED signal on row: %d and path: 0x%p\n", __FUNCTION__, row, path));
}
static void
item_double_click (ETableItem *eti, int row, int col, GdkEvent *event, ETree *et)
{
ETreePath path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
g_signal_emit (et,
et_signals [DOUBLE_CLICK], 0,
row, path, col, event);
}
static gint
item_right_click (ETableItem *eti, int row, int col, GdkEvent *event, ETree *et)
{
int return_val = 0;
ETreePath path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
g_signal_emit (et,
et_signals [RIGHT_CLICK], 0,
row, path, col, event, &return_val);
return return_val;
}
static gint
item_click (ETableItem *eti, int row, int col, GdkEvent *event, ETree *et)
{
int return_val = 0;
ETreePath path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
g_signal_emit (et,
et_signals [CLICK], 0,
row, path, col, event, &return_val);
return return_val;
}
static gint
item_key_press (ETableItem *eti, int row, int col, GdkEvent *event, ETree *et)
{
int return_val = 0;
GdkEventKey *key = (GdkEventKey *) event;
ETreePath path;
int y, row_local, col_local;
GtkAdjustment *vadj;
switch (key->keyval) {
case GDK_Page_Down:
case GDK_KP_Page_Down:
vadj = gtk_layout_get_vadjustment (GTK_LAYOUT (et->priv->table_canvas));
y = CLAMP(vadj->value + (2 * vadj->page_size - 50), 0, vadj->upper);
y -= vadj->value;
e_tree_get_cell_at (et, 30, y, &row_local, &col_local);
if (row_local == -1)
row_local = e_table_model_row_count (E_TABLE_MODEL(et->priv->etta)) - 1;
row_local = e_tree_view_to_model_row (et, row_local);
col_local = e_selection_model_cursor_col (E_SELECTION_MODEL (et->priv->selection));
e_selection_model_select_as_key_press (E_SELECTION_MODEL (et->priv->selection), row_local, col_local, key->state);
return_val = 1;
break;
case GDK_Page_Up:
case GDK_KP_Page_Up:
vadj = gtk_layout_get_vadjustment (GTK_LAYOUT (et->priv->table_canvas));
y = CLAMP(vadj->value - (vadj->page_size - 50), 0, vadj->upper);
y -= vadj->value;
e_tree_get_cell_at (et, 30, y, &row_local, &col_local);
if (row_local == -1)
row_local = e_table_model_row_count (E_TABLE_MODEL(et->priv->etta)) - 1;
row_local = e_tree_view_to_model_row (et, row_local);
col_local = e_selection_model_cursor_col (E_SELECTION_MODEL (et->priv->selection));
e_selection_model_select_as_key_press (E_SELECTION_MODEL (et->priv->selection), row_local, col_local, key->state);
return_val = 1;
break;
case '=':
case GDK_Right:
case GDK_KP_Right:
/* Only allow if the Shift modifier is used -- eg. Ctrl-Equal shouldn't be handled. */
if (key->state & ~(GDK_SHIFT_MASK | GDK_LOCK_MASK))
break;
if (row != -1) {
path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
if (path)
e_tree_table_adapter_node_set_expanded (et->priv->etta, path, TRUE);
}
return_val = 1;
break;
case '-':
case GDK_Left:
case GDK_KP_Left:
/* Only allow if the Shift modifier is used -- eg. Ctrl-Minus shouldn't be handled. */
if (key->state & ~(GDK_SHIFT_MASK | GDK_LOCK_MASK))
break;
if (row != -1) {
path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
if (path)
e_tree_table_adapter_node_set_expanded (et->priv->etta, path, FALSE);
}
return_val = 1;
break;
case GDK_BackSpace:
if (e_table_search_backspace (et->priv->search))
return TRUE;
/* Fallthrough */
default:
if ((key->state & ~(GDK_SHIFT_MASK | GDK_LOCK_MASK)) == 0
&& ((key->keyval >= GDK_a && key->keyval <= GDK_z) ||
(key->keyval >= GDK_A && key->keyval <= GDK_Z) ||
(key->keyval >= GDK_0 && key->keyval <= GDK_9))) {
e_table_search_input_character (et->priv->search, key->keyval);
}
path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
g_signal_emit (et,
et_signals [KEY_PRESS], 0,
row, path, col, event, &return_val);
break;
}
return return_val;
}
static gint
item_start_drag (ETableItem *eti, int row, int col, GdkEvent *event, ETree *et)
{
ETreePath path;
gint return_val = 0;
path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
g_signal_emit (et,
et_signals [START_DRAG], 0,
row, path, col, event, &return_val);
return return_val;
}
static void
et_selection_model_selection_changed (ETableSelectionModel *etsm, ETree *et)
{
g_signal_emit (et,
et_signals [SELECTION_CHANGE], 0);
}
static void
et_selection_model_selection_row_changed (ETableSelectionModel *etsm, int row, ETree *et)
{
g_signal_emit (et,
et_signals [SELECTION_CHANGE], 0);
}
static void
et_build_item (ETree *et)
{
et->priv->item = gnome_canvas_item_new(GNOME_CANVAS_GROUP (gnome_canvas_root(et->priv->table_canvas)),
e_table_item_get_type(),
"ETableHeader", et->priv->header,
"ETableModel", et->priv->etta,
"selection_model", et->priv->selection,
"alternating_row_colors", et->priv->alternating_row_colors,
"horizontal_draw_grid", et->priv->horizontal_draw_grid,
"vertical_draw_grid", et->priv->vertical_draw_grid,
"drawfocus", et->priv->draw_focus,
"cursor_mode", et->priv->cursor_mode,
"length_threshold", et->priv->length_threshold,
"uniform_row_height", et->priv->uniform_row_height,
NULL);
g_signal_connect (et->priv->item, "cursor_change",
G_CALLBACK (item_cursor_change), et);
g_signal_connect (et->priv->item, "cursor_activated",
G_CALLBACK (item_cursor_activated), et);
g_signal_connect (et->priv->item, "double_click",
G_CALLBACK (item_double_click), et);
g_signal_connect (et->priv->item, "right_click",
G_CALLBACK (item_right_click), et);
g_signal_connect (et->priv->item, "click",
G_CALLBACK (item_click), et);
g_signal_connect (et->priv->item, "key_press",
G_CALLBACK (item_key_press), et);
g_signal_connect (et->priv->item, "start_drag",
G_CALLBACK (item_start_drag), et);
}
static void
et_canvas_style_set (GtkWidget *widget, GtkStyle *prev_style)
{
gnome_canvas_item_set(
E_TREE(widget)->priv->white_item,
"fill_color_gdk", &widget->style->base[GTK_STATE_NORMAL],
NULL);
}
static gint
white_item_event (GnomeCanvasItem *white_item, GdkEvent *event, ETree *e_tree)
{
int return_val = 0;
g_signal_emit (e_tree,
et_signals [WHITE_SPACE_EVENT], 0,
event, &return_val);
return return_val;
}
static gint
et_canvas_root_event (GnomeCanvasItem *root, GdkEvent *event, ETree *e_tree)
{
switch (event->type) {
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
if (event->button.button != 4 && event->button.button != 5) {
if (GTK_WIDGET_HAS_FOCUS(root->canvas)) {
GnomeCanvasItem *item = GNOME_CANVAS(root->canvas)->focused_item;
if (E_IS_TABLE_ITEM(item)) {
e_table_item_leave_edit_(E_TABLE_ITEM(item));
return TRUE;
}
}
}
break;
default:
break;
}
return FALSE;
}
/* Handler for focus events in the table_canvas; we have to repaint ourselves
* and give the focus to some ETableItem.
*/
static gint
table_canvas_focus_event_cb (GtkWidget *widget, GdkEventFocus *event, gpointer data)
{
GnomeCanvas *canvas;
ETree *tree;
gtk_widget_queue_draw (widget);
if (!event->in)
return TRUE;
canvas = GNOME_CANVAS (widget);
tree = E_TREE (data);
if (!canvas->focused_item) {
e_table_item_set_cursor (E_TABLE_ITEM (tree->priv->item), 0, 0);
gnome_canvas_item_grab_focus (tree->priv->item);
}
return TRUE;
}
static void
e_tree_setup_table (ETree *e_tree)
{
e_tree->priv->table_canvas = GNOME_CANVAS (e_canvas_new ());
g_signal_connect (
e_tree->priv->table_canvas, "size_allocate",
G_CALLBACK (tree_canvas_size_allocate), e_tree);
g_signal_connect (
e_tree->priv->table_canvas, "focus_in_event",
G_CALLBACK (table_canvas_focus_event_cb), e_tree);
g_signal_connect (
e_tree->priv->table_canvas, "focus_out_event",
G_CALLBACK (table_canvas_focus_event_cb), e_tree);
g_signal_connect (
e_tree->priv->table_canvas, "drag_begin",
G_CALLBACK (et_drag_begin), e_tree);
g_signal_connect (
e_tree->priv->table_canvas, "drag_end",
G_CALLBACK (et_drag_end), e_tree);
g_signal_connect (
e_tree->priv->table_canvas, "drag_data_get",
G_CALLBACK (et_drag_data_get), e_tree);
g_signal_connect (
e_tree->priv->table_canvas, "drag_data_delete",
G_CALLBACK (et_drag_data_delete), e_tree);
g_signal_connect (
e_tree, "drag_motion",
G_CALLBACK (et_drag_motion), e_tree);
g_signal_connect (
e_tree, "drag_leave",
G_CALLBACK (et_drag_leave), e_tree);
g_signal_connect (
e_tree, "drag_drop",
G_CALLBACK (et_drag_drop), e_tree);
g_signal_connect (
e_tree, "drag_data_received",
G_CALLBACK (et_drag_data_received), e_tree);
g_signal_connect (e_tree->priv->table_canvas, "reflow",
G_CALLBACK (tree_canvas_reflow), e_tree);
gtk_widget_show (GTK_WIDGET (e_tree->priv->table_canvas));
e_tree->priv->white_item = gnome_canvas_item_new(
gnome_canvas_root(e_tree->priv->table_canvas),
e_canvas_background_get_type(),
"fill_color_gdk", &GTK_WIDGET(e_tree->priv->table_canvas)->style->base[GTK_STATE_NORMAL],
NULL);
g_signal_connect (e_tree->priv->white_item, "event",
G_CALLBACK (white_item_event), e_tree);
g_signal_connect (
gnome_canvas_root (e_tree->priv->table_canvas), "event",
G_CALLBACK(et_canvas_root_event), e_tree);
et_build_item(e_tree);
}
/**
* e_tree_set_search_column:
* @e_tree: #ETree object that will be modified
* @col: Column index to use for searches
*
* This routine sets the current search column to be used for keypress
* searches of the #ETree. If -1 is passed in for column, the current
* search column is cleared.
*/
void
e_tree_set_search_column (ETree *e_tree, gint col)
{
if (col == -1) {
clear_current_search_col (e_tree);
return;
}
e_tree->priv->search_col_set = TRUE;
e_tree->priv->current_search_col = e_table_header_get_column (e_tree->priv->full_header, col);
}
void
e_tree_set_state_object(ETree *e_tree, ETableState *state)
{
GValue *val = g_new0 (GValue, 1);
g_value_init (val, G_TYPE_DOUBLE);
connect_header (e_tree, state);
g_value_set_double (val, (double) (GTK_WIDGET(e_tree->priv->table_canvas)->allocation.width));
g_object_set_property (G_OBJECT (e_tree->priv->header), "width", val);
g_free (val);
if (e_tree->priv->header_item)
g_object_set(e_tree->priv->header_item,
"ETableHeader", e_tree->priv->header,
"sort_info", e_tree->priv->sort_info,
NULL);
if (e_tree->priv->item)
g_object_set(e_tree->priv->item,
"ETableHeader", e_tree->priv->header,
NULL);
if (e_tree->priv->etta)
e_tree_table_adapter_set_sort_info (e_tree->priv->etta, e_tree->priv->sort_info);
e_tree_state_change (e_tree);
}
/**
* e_tree_set_state:
* @e_tree: #ETree object that will be modified
* @state_str: a string with the XML representation of the #ETableState.
*
* This routine sets the state (as described by #ETableState) of the
* #ETree object.
*/
void
e_tree_set_state (ETree *e_tree,
const gchar *state_str)
{
ETableState *state;
g_return_if_fail(e_tree != NULL);
g_return_if_fail(E_IS_TREE(e_tree));
g_return_if_fail(state_str != NULL);
state = e_table_state_new();
e_table_state_load_from_string(state, state_str);
if (state->col_count > 0)
e_tree_set_state_object(e_tree, state);
g_object_unref(state);
}
/**
* e_tree_load_state:
* @e_tree: #ETree object that will be modified
* @filename: name of the file containing the state to be loaded into the #ETree
*
* An #ETableState will be loaded form the file pointed by @filename into the
* @e_tree object.
*/
void
e_tree_load_state (ETree *e_tree,
const gchar *filename)
{
ETableState *state;
g_return_if_fail(e_tree != NULL);
g_return_if_fail(E_IS_TREE(e_tree));
g_return_if_fail(filename != NULL);
state = e_table_state_new();
e_table_state_load_from_file(state, filename);
if (state->col_count > 0)
e_tree_set_state_object(e_tree, state);
g_object_unref(state);
}
/**
* e_tree_get_state_object:
* @e_tree: #ETree object to act on
*
* Builds an #ETableState corresponding to the current state of the
* #ETree.
*
* Return value:
* The %ETableState object generated.
**/
ETableState *
e_tree_get_state_object (ETree *e_tree)
{
ETableState *state;
int full_col_count;
int i, j;
state = e_table_state_new();
state->sort_info = e_tree->priv->sort_info;
if (state->sort_info)
g_object_ref(state->sort_info);
state->col_count = e_table_header_count (e_tree->priv->header);
full_col_count = e_table_header_count (e_tree->priv->full_header);
state->columns = g_new(int, state->col_count);
state->expansions = g_new(double, state->col_count);
for (i = 0; i < state->col_count; i++) {
ETableCol *col = e_table_header_get_column(e_tree->priv->header, i);
state->columns[i] = -1;
for (j = 0; j < full_col_count; j++) {
if (col->col_idx == e_table_header_index(e_tree->priv->full_header, j)) {
state->columns[i] = j;
break;
}
}
state->expansions[i] = col->expansion;
}
return state;
}
/**
* e_tree_get_state:
* @e_tree: The #ETree to act on
*
* Builds a state object based on the current state and returns the
* string corresponding to that state.
*
* Return value:
* A string describing the current state of the #ETree.
**/
gchar *
e_tree_get_state (ETree *e_tree)
{
ETableState *state;
gchar *string;
state = e_tree_get_state_object(e_tree);
string = e_table_state_save_to_string(state);
g_object_unref(state);
return string;
}
/**
* e_tree_save_state:
* @e_tree: The #ETree to act on
* @filename: name of the file to save to
*
* Saves the state of the @e_tree object into the file pointed by
* @filename.
**/
void
e_tree_save_state (ETree *e_tree,
const gchar *filename)
{
ETableState *state;
state = e_tree_get_state_object(e_tree);
e_table_state_save_to_file(state, filename);
g_object_unref(state);
}
/**
* e_tree_get_spec:
* @e_tree: The #ETree to query
*
* Returns the specification object.
*
* Return value:
**/
ETableSpecification *
e_tree_get_spec (ETree *e_tree)
{
return e_tree->priv->spec;
}
static void
et_table_model_changed (ETableModel *model, ETree *et)
{
if (et->priv->horizontal_scrolling)
e_table_header_update_horizontal(et->priv->header);
}
static void
et_table_row_changed (ETableModel *table_model, int row, ETree *et)
{
et_table_model_changed (table_model, et);
}
static void
et_table_cell_changed (ETableModel *table_model, int view_col, int row, ETree *et)
{
et_table_model_changed (table_model, et);
}
static void
et_connect_to_etta (ETree *et)
{
et->priv->table_model_change_id = g_signal_connect (et->priv->etta, "model_changed",
G_CALLBACK (et_table_model_changed), et);
et->priv->table_row_change_id = g_signal_connect (et->priv->etta, "model_row_changed",
G_CALLBACK (et_table_row_changed), et);
et->priv->table_cell_change_id = g_signal_connect (et->priv->etta, "model_cell_changed",
G_CALLBACK (et_table_cell_changed), et);
}
static ETree *
et_real_construct (ETree *e_tree, ETreeModel *etm, ETableExtras *ete,
ETableSpecification *specification, ETableState *state)
{
int row = 0;
if (ete)
g_object_ref(ete);
else
ete = e_table_extras_new();
e_tree->priv->alternating_row_colors = specification->alternating_row_colors;
e_tree->priv->horizontal_draw_grid = specification->horizontal_draw_grid;
e_tree->priv->vertical_draw_grid = specification->vertical_draw_grid;
e_tree->priv->draw_focus = specification->draw_focus;
e_tree->priv->cursor_mode = specification->cursor_mode;
e_tree->priv->full_header = e_table_spec_to_full_header(specification, ete);
connect_header (e_tree, state);
e_tree->priv->horizontal_scrolling = specification->horizontal_scrolling;
e_tree->priv->model = etm;
g_object_ref (etm);
e_tree->priv->etta = E_TREE_TABLE_ADAPTER(e_tree_table_adapter_new(e_tree->priv->model, e_tree->priv->sort_info, e_tree->priv->full_header));
et_connect_to_etta (e_tree);
gtk_widget_push_colormap (gdk_rgb_get_cmap ());
e_tree->priv->sorter = e_sorter_new();
g_object_set (e_tree->priv->selection,
"sorter", e_tree->priv->sorter,
#ifdef E_TREE_USE_TREE_SELECTION
"model", e_tree->priv->model,
"etta", e_tree->priv->etta,
#else
"model", e_tree->priv->etta,
#endif
"selection_mode", specification->selection_mode,
"cursor_mode", specification->cursor_mode,
NULL);
g_signal_connect(e_tree->priv->selection, "selection_changed",
G_CALLBACK (et_selection_model_selection_changed), e_tree);
g_signal_connect(e_tree->priv->selection, "selection_row_changed",
G_CALLBACK (et_selection_model_selection_row_changed), e_tree);
if (!specification->no_headers) {
e_tree_setup_header (e_tree);
}
e_tree_setup_table (e_tree);
gtk_layout_get_vadjustment (GTK_LAYOUT (e_tree->priv->table_canvas))->step_increment = 20;
gtk_adjustment_changed(gtk_layout_get_vadjustment (GTK_LAYOUT (e_tree->priv->table_canvas)));
gtk_layout_get_hadjustment (GTK_LAYOUT (e_tree->priv->table_canvas))->step_increment = 20;
gtk_adjustment_changed(gtk_layout_get_hadjustment (GTK_LAYOUT (e_tree->priv->table_canvas)));
if (!specification->no_headers) {
/*
* The header
*/
gtk_table_attach (GTK_TABLE (e_tree), GTK_WIDGET (e_tree->priv->header_canvas),
0, 1, 0 + row, 1 + row,
GTK_FILL | GTK_EXPAND,
GTK_FILL, 0, 0);
row ++;
}
gtk_table_attach (GTK_TABLE (e_tree), GTK_WIDGET (e_tree->priv->table_canvas),
0, 1, 0 + row, 1 + row,
GTK_FILL | GTK_EXPAND,
GTK_FILL | GTK_EXPAND,
0, 0);
gtk_widget_pop_colormap ();
g_object_unref(ete);
return e_tree;
}
/**
* e_tree_construct:
* @e_tree: The newly created #ETree object.
* @etm: The model for this table.
* @ete: An optional #ETableExtras. (%NULL is valid.)
* @spec_str: The spec.
* @state_str: An optional state. (%NULL is valid.)
*
* This is the internal implementation of e_tree_new() for use by
* subclasses or language bindings. See e_tree_new() for details.
*
* Return value:
* The passed in value @e_tree or %NULL if there's an error.
**/
ETree *
e_tree_construct (ETree *e_tree, ETreeModel *etm, ETableExtras *ete,
const char *spec_str, const char *state_str)
{
ETableSpecification *specification;
ETableState *state;
g_return_val_if_fail(e_tree != NULL, NULL);
g_return_val_if_fail(E_IS_TREE(e_tree), NULL);
g_return_val_if_fail(etm != NULL, NULL);
g_return_val_if_fail(E_IS_TREE_MODEL(etm), NULL);
g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
g_return_val_if_fail(spec_str != NULL, NULL);
specification = e_table_specification_new();
e_table_specification_load_from_string(specification, spec_str);
if (state_str) {
state = e_table_state_new();
e_table_state_load_from_string(state, state_str);
if (state->col_count <= 0) {
g_object_unref(state);
state = specification->state;
g_object_ref(state);
}
} else {
state = specification->state;
g_object_ref(state);
}
e_tree = et_real_construct (e_tree, etm, ete, specification, state);
e_tree->priv->spec = specification;
g_object_unref(state);
return e_tree;
}
/**
* e_tree_construct_from_spec_file:
* @e_tree: The newly created #ETree object.
* @etm: The model for this tree
* @ete: An optional #ETableExtras (%NULL is valid.)
* @spec_fn: The filename of the spec
* @state_fn: An optional state file (%NULL is valid.)
*
* This is the internal implementation of e_tree_new_from_spec_file()
* for use by subclasses or language bindings. See
* e_tree_new_from_spec_file() for details.
*
* Return value:
* The passed in value @e_tree or %NULL if there's an error.
**/
ETree *
e_tree_construct_from_spec_file (ETree *e_tree, ETreeModel *etm, ETableExtras *ete,
const char *spec_fn, const char *state_fn)
{
ETableSpecification *specification;
ETableState *state;
g_return_val_if_fail(e_tree != NULL, NULL);
g_return_val_if_fail(E_IS_TREE(e_tree), NULL);
g_return_val_if_fail(etm != NULL, NULL);
g_return_val_if_fail(E_IS_TREE_MODEL(etm), NULL);
g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
g_return_val_if_fail(spec_fn != NULL, NULL);
specification = e_table_specification_new();
if (!e_table_specification_load_from_file(specification, spec_fn)) {
g_object_unref(specification);
return NULL;
}
if (state_fn) {
state = e_table_state_new();
if (!e_table_state_load_from_file(state, state_fn)) {
g_object_unref(state);
state = specification->state;
g_object_ref(state);
}
if (state->col_count <= 0) {
g_object_unref(state);
state = specification->state;
g_object_ref(state);
}
} else {
state = specification->state;
g_object_ref(state);
}
e_tree = et_real_construct (e_tree, etm, ete, specification, state);
e_tree->priv->spec = specification;
g_object_unref(state);
return e_tree;
}
/**
* e_tree_new:
* @etm: The model for this tree
* @ete: An optional #ETableExtras (%NULL is valid.)
* @spec: The spec
* @state: An optional state (%NULL is valid.)
*
* This function creates an #ETree from the given parameters. The
* #ETreeModel is a tree model to be represented. The #ETableExtras
* is an optional set of pixbufs, cells, and sorting functions to be
* used when interpreting the spec. If you pass in %NULL it uses the
* default #ETableExtras. (See e_table_extras_new()).
*
* @spec is the specification of the set of viewable columns and the
* default sorting state and such. @state is an optional string
* specifying the current sorting state and such. If @state is NULL,
* then the default state from the spec will be used.
*
* Return value:
* The newly created #ETree or %NULL if there's an error.
**/
GtkWidget *
e_tree_new (ETreeModel *etm, ETableExtras *ete, const char *spec, const char *state)
{
ETree *e_tree, *ret_val;
g_return_val_if_fail(etm != NULL, NULL);
g_return_val_if_fail(E_IS_TREE_MODEL(etm), NULL);
g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
g_return_val_if_fail(spec != NULL, NULL);
e_tree = g_object_new (E_TREE_TYPE, NULL);
ret_val = e_tree_construct (e_tree, etm, ete, spec, state);
if (ret_val == NULL) {
g_object_unref (e_tree);
}
return (GtkWidget *) ret_val;
}
/**
* e_tree_new_from_spec_file:
* @etm: The model for this tree.
* @ete: An optional #ETableExtras. (%NULL is valid.)
* @spec_fn: The filename of the spec.
* @state_fn: An optional state file. (%NULL is valid.)
*
* This is very similar to e_tree_new(), except instead of passing in
* strings you pass in the file names of the spec and state to load.
*
* @spec_fn is the filename of the spec to load. If this file doesn't
* exist, e_tree_new_from_spec_file will return %NULL.
*
* @state_fn is the filename of the initial state to load. If this is
* %NULL or if the specified file doesn't exist, the default state
* from the spec file is used.
*
* Return value:
* The newly created #ETree or %NULL if there's an error.
**/
GtkWidget *
e_tree_new_from_spec_file (ETreeModel *etm, ETableExtras *ete, const char *spec_fn, const char *state_fn)
{
ETree *e_tree, *ret_val;
g_return_val_if_fail(etm != NULL, NULL);
g_return_val_if_fail(E_IS_TREE_MODEL(etm), NULL);
g_return_val_if_fail(ete == NULL || E_IS_TABLE_EXTRAS(ete), NULL);
g_return_val_if_fail(spec_fn != NULL, NULL);
e_tree = g_object_new (E_TREE_TYPE, NULL);
ret_val = e_tree_construct_from_spec_file (e_tree, etm, ete, spec_fn, state_fn);
if (ret_val == NULL) {
g_object_unref (e_tree);
}
return (GtkWidget *) ret_val;
}
void
e_tree_set_cursor (ETree *e_tree, ETreePath path)
{
#ifndef E_TREE_USE_TREE_SELECTION
int row;
#endif
g_return_if_fail(e_tree != NULL);
g_return_if_fail(E_IS_TREE(e_tree));
g_return_if_fail(path != NULL);
#ifdef E_TREE_USE_TREE_SELECTION
e_tree_selection_model_select_single_path (E_TREE_SELECTION_MODEL(e_tree->priv->selection), path);
e_tree_selection_model_change_cursor (E_TREE_SELECTION_MODEL(e_tree->priv->selection), path);
#else
row = e_tree_table_adapter_row_of_node(E_TREE_TABLE_ADAPTER(e_tree->priv->etta), path);
if (row == -1)
return;
g_object_set(e_tree->priv->selection,
"cursor_row", row,
NULL);
#endif
}
ETreePath
e_tree_get_cursor (ETree *e_tree)
{
#ifdef E_TREE_USE_TREE_SELECTION
return e_tree_selection_model_get_cursor (E_TREE_SELECTION_MODEL(e_tree->priv->selection));
#else
int row;
ETreePath path;
g_return_val_if_fail(e_tree != NULL, NULL);
g_return_val_if_fail(E_IS_TREE(e_tree), NULL);
g_object_get(e_tree->priv->selection,
"cursor_row", &row,
NULL);
if (row == -1)
return NULL;
path = e_tree_table_adapter_node_at_row(E_TREE_TABLE_ADAPTER(e_tree->priv->etta), row);
return path;
#endif
}
void
e_tree_selected_row_foreach (ETree *e_tree,
EForeachFunc callback,
gpointer closure)
{
g_return_if_fail(e_tree != NULL);
g_return_if_fail(E_IS_TREE(e_tree));
e_selection_model_foreach(e_tree->priv->selection,
callback,
closure);
}
#ifdef E_TREE_USE_TREE_SELECTION
void
e_tree_selected_path_foreach (ETree *e_tree,
ETreeForeachFunc callback,
gpointer closure)
{
g_return_if_fail(e_tree != NULL);
g_return_if_fail(E_IS_TREE(e_tree));
e_tree_selection_model_foreach(E_TREE_SELECTION_MODEL (e_tree->priv->selection),
callback,
closure);
}
/* Standard functions */
static void
et_foreach_recurse (ETreeModel *model,
ETreePath path,
ETreeForeachFunc callback,
gpointer closure)
{
ETreePath child;
callback(path, closure);
child = e_tree_model_node_get_first_child(E_TREE_MODEL(model), path);
for ( ; child; child = e_tree_model_node_get_next(E_TREE_MODEL(model), child))
if (child)
et_foreach_recurse (model, child, callback, closure);
}
void
e_tree_path_foreach (ETree *e_tree,
ETreeForeachFunc callback,
gpointer closure)
{
ETreePath root;
g_return_if_fail(e_tree != NULL);
g_return_if_fail(E_IS_TREE(e_tree));
root = e_tree_model_get_root (e_tree->priv->model);
if (root)
et_foreach_recurse (e_tree->priv->model,
root,
callback,
closure);
}
#endif
EPrintable *
e_tree_get_printable (ETree *e_tree)
{
g_return_val_if_fail(e_tree != NULL, NULL);
g_return_val_if_fail(E_IS_TREE(e_tree), NULL);
return e_table_item_get_printable(E_TABLE_ITEM(e_tree->priv->item));
}
static void
et_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ETree *etree = E_TREE (object);
switch (prop_id){
case PROP_ETTA:
g_value_set_object (value, etree->priv->etta);
break;
case PROP_UNIFORM_ROW_HEIGHT:
g_value_set_boolean (value, etree->priv->uniform_row_height);
break;
case PROP_ALWAYS_SEARCH:
g_value_set_boolean (value, etree->priv->always_search);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
typedef struct {
char *arg;
gboolean setting;
} bool_closure;
static void
et_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ETree *etree = E_TREE (object);
switch (prop_id){
case PROP_LENGTH_THRESHOLD:
etree->priv->length_threshold = g_value_get_int (value);
if (etree->priv->item) {
gnome_canvas_item_set (GNOME_CANVAS_ITEM(etree->priv->item),
"length_threshold", etree->priv->length_threshold,
NULL);
}
break;
case PROP_HORIZONTAL_DRAW_GRID:
etree->priv->horizontal_draw_grid = g_value_get_boolean (value);
if (etree->priv->item) {
gnome_canvas_item_set (GNOME_CANVAS_ITEM(etree->priv->item),
"horizontal_draw_grid", etree->priv->horizontal_draw_grid,
NULL);
}
break;
case PROP_VERTICAL_DRAW_GRID:
etree->priv->vertical_draw_grid = g_value_get_boolean (value);
if (etree->priv->item) {
gnome_canvas_item_set (GNOME_CANVAS_ITEM(etree->priv->item),
"vertical_draw_grid", etree->priv->vertical_draw_grid,
NULL);
}
break;
case PROP_DRAW_FOCUS:
etree->priv->draw_focus = g_value_get_boolean (value);
if (etree->priv->item) {
gnome_canvas_item_set (GNOME_CANVAS_ITEM(etree->priv->item),
"drawfocus", etree->priv->draw_focus,
NULL);
}
break;
case PROP_UNIFORM_ROW_HEIGHT:
etree->priv->uniform_row_height = g_value_get_boolean (value);
if (etree->priv->item) {
gnome_canvas_item_set (GNOME_CANVAS_ITEM(etree->priv->item),
"uniform_row_height", etree->priv->uniform_row_height,
NULL);
}
break;
case PROP_ALWAYS_SEARCH:
if (etree->priv->always_search == g_value_get_boolean (value))
return;
etree->priv->always_search = g_value_get_boolean (value);
clear_current_search_col (etree);
break;
}
}
static void
set_scroll_adjustments (ETree *tree,
GtkAdjustment *hadjustment,
GtkAdjustment *vadjustment)
{
if (vadjustment != NULL) {
vadjustment->step_increment = 20;
gtk_adjustment_changed(vadjustment);
}
if (hadjustment != NULL) {
hadjustment->step_increment = 20;
gtk_adjustment_changed(hadjustment);
}
if (tree->priv) {
gtk_layout_set_hadjustment (GTK_LAYOUT(tree->priv->table_canvas),
hadjustment);
gtk_layout_set_vadjustment (GTK_LAYOUT(tree->priv->table_canvas),
vadjustment);
if (tree->priv->header_canvas != NULL)
gtk_layout_set_hadjustment (GTK_LAYOUT(tree->priv->header_canvas),
hadjustment);
}
}
gint
e_tree_get_next_row (ETree *e_tree,
gint model_row)
{
g_return_val_if_fail(e_tree != NULL, -1);
g_return_val_if_fail(E_IS_TREE(e_tree), -1);
if (e_tree->priv->sorter) {
int i;
i = e_sorter_model_to_sorted(E_SORTER (e_tree->priv->sorter), model_row);
i++;
if (i < e_table_model_row_count(E_TABLE_MODEL(e_tree->priv->etta))) {
return e_sorter_sorted_to_model(E_SORTER (e_tree->priv->sorter), i);
} else
return -1;
} else
if (model_row < e_table_model_row_count(E_TABLE_MODEL(e_tree->priv->etta)) - 1)
return model_row + 1;
else
return -1;
}
gint
e_tree_get_prev_row (ETree *e_tree,
gint model_row)
{
g_return_val_if_fail(e_tree != NULL, -1);
g_return_val_if_fail(E_IS_TREE(e_tree), -1);
if (e_tree->priv->sorter) {
int i;
i = e_sorter_model_to_sorted(E_SORTER (e_tree->priv->sorter), model_row);
i--;
if (i >= 0)
return e_sorter_sorted_to_model(E_SORTER (e_tree->priv->sorter), i);
else
return -1;
} else
return model_row - 1;
}
gint
e_tree_model_to_view_row (ETree *e_tree,
gint model_row)
{
g_return_val_if_fail(e_tree != NULL, -1);
g_return_val_if_fail(E_IS_TREE(e_tree), -1);
if (e_tree->priv->sorter)
return e_sorter_model_to_sorted(E_SORTER (e_tree->priv->sorter), model_row);
else
return model_row;
}
gint
e_tree_view_to_model_row (ETree *e_tree,
gint view_row)
{
g_return_val_if_fail(e_tree != NULL, -1);
g_return_val_if_fail(E_IS_TREE(e_tree), -1);
if (e_tree->priv->sorter)
return e_sorter_sorted_to_model (E_SORTER (e_tree->priv->sorter), view_row);
else
return view_row;
}
gboolean
e_tree_node_is_expanded (ETree *et, ETreePath path)
{
g_return_val_if_fail(path, FALSE);
return e_tree_table_adapter_node_is_expanded (et->priv->etta, path);
}
void
e_tree_node_set_expanded (ETree *et, ETreePath path, gboolean expanded)
{
g_return_if_fail (et != NULL);
g_return_if_fail (E_IS_TREE(et));
e_tree_table_adapter_node_set_expanded (et->priv->etta, path, expanded);
}
void
e_tree_node_set_expanded_recurse (ETree *et, ETreePath path, gboolean expanded)
{
g_return_if_fail (et != NULL);
g_return_if_fail (E_IS_TREE(et));
e_tree_table_adapter_node_set_expanded_recurse (et->priv->etta, path, expanded);
}
void
e_tree_root_node_set_visible (ETree *et, gboolean visible)
{
g_return_if_fail (et != NULL);
g_return_if_fail (E_IS_TREE(et));
e_tree_table_adapter_root_node_set_visible (et->priv->etta, visible);
}
ETreePath
e_tree_node_at_row (ETree *et, int row)
{
ETreePath path;
path = e_tree_table_adapter_node_at_row (et->priv->etta, row);
return path;
}
int
e_tree_row_of_node (ETree *et, ETreePath path)
{
return e_tree_table_adapter_row_of_node (et->priv->etta, path);
}
gboolean
e_tree_root_node_is_visible(ETree *et)
{
return e_tree_table_adapter_root_node_is_visible (et->priv->etta);
}
void
e_tree_show_node (ETree *et, ETreePath path)
{
g_return_if_fail (et != NULL);
g_return_if_fail (E_IS_TREE(et));
e_tree_table_adapter_show_node (et->priv->etta, path);
}
void
e_tree_save_expanded_state (ETree *et, char *filename)
{
g_return_if_fail (et != NULL);
g_return_if_fail (E_IS_TREE(et));
e_tree_table_adapter_save_expanded_state (et->priv->etta, filename);
}
void
e_tree_load_expanded_state (ETree *et, char *filename)
{
e_tree_table_adapter_load_expanded_state (et->priv->etta, filename);
}
gint
e_tree_row_count (ETree *et)
{
return e_table_model_row_count (E_TABLE_MODEL(et->priv->etta));
}
GtkWidget *
e_tree_get_tooltip (ETree *et)
{
return E_CANVAS(et->priv->table_canvas)->tooltip_window;
}
static ETreePath
find_next_in_range (ETree *et, gint start, gint end, ETreePathFunc func, gpointer data)
{
ETreePath path;
gint row;
for (row = start; row <= end; row++) {
path = e_tree_table_adapter_node_at_row (et->priv->etta, row);
if (path && func (et->priv->model, path, data))
return path;
}
return NULL;
}
static ETreePath
find_prev_in_range (ETree *et, gint start, gint end, ETreePathFunc func, gpointer data)
{
ETreePath path;
gint row;
for (row = start; row >= end; row--) {
path = e_tree_table_adapter_node_at_row (et->priv->etta, row);
if (path && func (et->priv->model, path, data))
return path;
}
return NULL;
}
gboolean
e_tree_find_next (ETree *et, ETreeFindNextParams params, ETreePathFunc func, gpointer data)
{
ETreePath cursor, found;
gint row, row_count;
cursor = e_tree_get_cursor (et);
row = e_tree_table_adapter_row_of_node (et->priv->etta, cursor);
row_count = e_table_model_row_count (E_TABLE_MODEL (et->priv->etta));
if (params & E_TREE_FIND_NEXT_FORWARD)
found = find_next_in_range (et, row + 1, row_count - 1, func, data);
else
found = find_prev_in_range (et, row == -1 ? -1 : row - 1, 0, func, data);
if (found) {
e_tree_table_adapter_show_node (et->priv->etta, found);
e_tree_set_cursor (et, found);
return TRUE;
}
if (params & E_TREE_FIND_NEXT_WRAP) {
if (params & E_TREE_FIND_NEXT_FORWARD)
found = find_next_in_range (et, 0, row, func, data);
else
found = find_prev_in_range (et, row_count - 1, row, func, data);
if (found && found != cursor) {
e_tree_table_adapter_show_node (et->priv->etta, found);
e_tree_set_cursor (et, found);
return TRUE;
}
}
return FALSE;
}
void
e_tree_right_click_up (ETree *et)
{
e_selection_model_right_click_up(et->priv->selection);
}
/**
* e_tree_get_model:
* @et: the ETree
*
* Returns the model upon which this ETree is based.
*
* Returns: the model
**/
ETreeModel *
e_tree_get_model (ETree *et)
{
g_return_val_if_fail (et != NULL, NULL);
g_return_val_if_fail (E_IS_TREE (et), NULL);
return et->priv->model;
}
/**
* e_tree_get_selection_model:
* @et: the ETree
*
* Returns the selection model of this ETree.
*
* Returns: the selection model
**/
ESelectionModel *
e_tree_get_selection_model (ETree *et)
{
g_return_val_if_fail (et != NULL, NULL);
g_return_val_if_fail (E_IS_TREE (et), NULL);
return et->priv->selection;
}
/**
* e_tree_get_table_adapter:
* @et: the ETree
*
* Returns the table adapter this ETree uses.
*
* Returns: the model
**/
ETreeTableAdapter *
e_tree_get_table_adapter (ETree *et)
{
g_return_val_if_fail (et != NULL, NULL);
g_return_val_if_fail (E_IS_TREE (et), NULL);
return et->priv->etta;
}
ETableItem *
e_tree_get_item(ETree * et)
{
g_return_val_if_fail (et != NULL, NULL);
g_return_val_if_fail (E_IS_TREE (et), NULL);
return E_TABLE_ITEM (et->priv->item);
}
struct _ETreeDragSourceSite
{
GdkModifierType start_button_mask;
GtkTargetList *target_list; /* Targets for drag data */
GdkDragAction actions; /* Possible actions */
GdkColormap *colormap; /* Colormap for drag icon */
GdkPixmap *pixmap; /* Icon for drag data */
GdkBitmap *mask;
/* Stored button press information to detect drag beginning */
gint state;
gint x, y;
gint row, col;
};
typedef enum
{
GTK_DRAG_STATUS_DRAG,
GTK_DRAG_STATUS_WAIT,
GTK_DRAG_STATUS_DROP
} GtkDragStatus;
typedef struct _GtkDragDestInfo GtkDragDestInfo;
typedef struct _GtkDragSourceInfo GtkDragSourceInfo;
struct _GtkDragDestInfo
{
GtkWidget *widget; /* Widget in which drag is in */
GdkDragContext *context; /* Drag context */
GtkDragSourceInfo *proxy_source; /* Set if this is a proxy drag */
GtkSelectionData *proxy_data; /* Set while retrieving proxied data */
gboolean dropped : 1; /* Set after we receive a drop */
guint32 proxy_drop_time; /* Timestamp for proxied drop */
gboolean proxy_drop_wait : 1; /* Set if we are waiting for a
* status reply before sending
* a proxied drop on.
*/
gint drop_x, drop_y; /* Position of drop */
};
struct _GtkDragSourceInfo
{
GtkWidget *widget;
GtkTargetList *target_list; /* Targets for drag data */
GdkDragAction possible_actions; /* Actions allowed by source */
GdkDragContext *context; /* drag context */
GtkWidget *icon_window; /* Window for drag */
GtkWidget *ipc_widget; /* GtkInvisible for grab, message passing */
GdkCursor *cursor; /* Cursor for drag */
gint hot_x, hot_y; /* Hot spot for drag */
gint button; /* mouse button starting drag */
GtkDragStatus status; /* drag status */
GdkEvent *last_event; /* motion event waiting for response */
gint start_x, start_y; /* Initial position */
gint cur_x, cur_y; /* Current Position */
GList *selections; /* selections we've claimed */
GtkDragDestInfo *proxy_dest; /* Set if this is a proxy drag */
guint drop_timeout; /* Timeout for aborting drop */
guint destroy_icon : 1; /* If true, destroy icon_window
*/
};
/* Drag & drop stuff. */
/* Target */
void
e_tree_drag_get_data (ETree *tree,
int row,
int col,
GdkDragContext *context,
GdkAtom target,
guint32 time)
{
ETreePath path;
g_return_if_fail(tree != NULL);
g_return_if_fail(E_IS_TREE(tree));
path = e_tree_table_adapter_node_at_row(tree->priv->etta, row);
gtk_drag_get_data(GTK_WIDGET(tree),
context,
target,
time);
}
/**
* e_tree_drag_highlight:
* @tree:
* @row:
* @col:
*
* Set col to -1 to highlight the entire row.
* Set row to -1 to turn off the highlight.
*/
void
e_tree_drag_highlight (ETree *tree,
int row,
int col)
{
g_return_if_fail(tree != NULL);
g_return_if_fail(E_IS_TREE(tree));
if (row != -1) {
int x, y, width, height;
if (col == -1) {
e_tree_get_cell_geometry (tree, row, 0, &x, &y, &width, &height);
x = 0;
width = GTK_WIDGET (tree->priv->table_canvas)->allocation.width;
} else {
e_tree_get_cell_geometry (tree, row, col, &x, &y, &width, &height);
x += GTK_LAYOUT(tree->priv->table_canvas)->hadjustment->value;
}
y += GTK_LAYOUT(tree->priv->table_canvas)->vadjustment->value;
if (tree->priv->drop_highlight == NULL) {
tree->priv->drop_highlight =
gnome_canvas_item_new (gnome_canvas_root (tree->priv->table_canvas),
gnome_canvas_rect_get_type (),
"fill_color", NULL,
/* "outline_color", "black",
"width_pixels", 1,*/
"outline_color_gdk", &(GTK_WIDGET (tree)->style->fg[GTK_STATE_NORMAL]),
NULL);
}
gnome_canvas_item_set (tree->priv->drop_highlight,
"x1", (double) x,
"x2", (double) x + width - 1,
"y1", (double) y,
"y2", (double) y + height - 1,
NULL);
} else {
gtk_object_destroy (GTK_OBJECT (tree->priv->drop_highlight));
tree->priv->drop_highlight = NULL;
}
}
void
e_tree_drag_unhighlight (ETree *tree)
{
g_return_if_fail(tree != NULL);
g_return_if_fail(E_IS_TREE(tree));
if (tree->priv->drop_highlight) {
gtk_object_destroy (GTK_OBJECT (tree->priv->drop_highlight));
tree->priv->drop_highlight = NULL;
}
}
void e_tree_drag_dest_set (ETree *tree,
GtkDestDefaults flags,
const GtkTargetEntry *targets,
gint n_targets,
GdkDragAction actions)
{
g_return_if_fail(tree != NULL);
g_return_if_fail(E_IS_TREE(tree));
gtk_drag_dest_set(GTK_WIDGET(tree),
flags,
targets,
n_targets,
actions);
}
void e_tree_drag_dest_set_proxy (ETree *tree,
GdkWindow *proxy_window,
GdkDragProtocol protocol,
gboolean use_coordinates)
{
g_return_if_fail(tree != NULL);
g_return_if_fail(E_IS_TREE(tree));
gtk_drag_dest_set_proxy(GTK_WIDGET(tree),
proxy_window,
protocol,
use_coordinates);
}
/*
* There probably should be functions for setting the targets
* as a GtkTargetList
*/
void
e_tree_drag_dest_unset (GtkWidget *widget)
{
g_return_if_fail(widget != NULL);
g_return_if_fail(E_IS_TREE(widget));
gtk_drag_dest_unset(widget);
}
/* Source side */
static gint
et_real_start_drag (ETree *tree, int row, ETreePath path, int col, GdkEvent *event)
{
GtkDragSourceInfo *info;
GdkDragContext *context;
ETreeDragSourceSite *site;
if (tree->priv->do_drag) {
site = tree->priv->site;
site->state = 0;
context = e_tree_drag_begin (tree, row, col,
site->target_list,
site->actions,
1, event);
if (context) {
info = g_dataset_get_data (context, "gtk-info");
if (info && !info->icon_window) {
if (site->pixmap)
gtk_drag_set_icon_pixmap (context,
site->colormap,
site->pixmap,
site->mask, -2, -2);
else
gtk_drag_set_icon_default (context);
}
}
return TRUE;
}
return FALSE;
}
void
e_tree_drag_source_set (ETree *tree,
GdkModifierType start_button_mask,
const GtkTargetEntry *targets,
gint n_targets,
GdkDragAction actions)
{
ETreeDragSourceSite *site;
GtkWidget *canvas;
g_return_if_fail(tree != NULL);
g_return_if_fail(E_IS_TREE(tree));
canvas = GTK_WIDGET(tree->priv->table_canvas);
site = tree->priv->site;
tree->priv->do_drag = TRUE;
gtk_widget_add_events (canvas,
gtk_widget_get_events (canvas) |
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
GDK_BUTTON_MOTION_MASK | GDK_STRUCTURE_MASK);
if (site) {
if (site->target_list)
gtk_target_list_unref (site->target_list);
} else {
site = g_new0 (ETreeDragSourceSite, 1);
tree->priv->site = site;
}
site->start_button_mask = start_button_mask;
if (targets)
site->target_list = gtk_target_list_new (targets, n_targets);
else
site->target_list = NULL;
site->actions = actions;
}
void
e_tree_drag_source_unset (ETree *tree)
{
ETreeDragSourceSite *site;
g_return_if_fail (tree != NULL);
g_return_if_fail (E_IS_TREE(tree));
site = tree->priv->site;
if (site) {
if (site->target_list)
gtk_target_list_unref (site->target_list);
g_free (site);
tree->priv->site = NULL;
}
}
/* There probably should be functions for setting the targets
* as a GtkTargetList
*/
GdkDragContext *
e_tree_drag_begin (ETree *tree,
int row,
int col,
GtkTargetList *targets,
GdkDragAction actions,
gint button,
GdkEvent *event)
{
ETreePath path;
g_return_val_if_fail (tree != NULL, NULL);
g_return_val_if_fail (E_IS_TREE(tree), NULL);
path = e_tree_table_adapter_node_at_row(tree->priv->etta, row);
tree->priv->drag_row = row;
tree->priv->drag_path = path;
tree->priv->drag_col = col;
return gtk_drag_begin(GTK_WIDGET (tree->priv->table_canvas),
targets,
actions,
button,
event);
}
/**
* e_tree_get_cell_at:
* @tree: An ETree widget
* @x: X coordinate for the pixel
* @y: Y coordinate for the pixel
* @row_return: Pointer to return the row value
* @col_return: Pointer to return the column value
*
* Return the row and column for the cell in which the pixel at (@x, @y) is
* contained.
**/
void
e_tree_get_cell_at (ETree *tree,
int x, int y,
int *row_return, int *col_return)
{
g_return_if_fail (tree != NULL);
g_return_if_fail (E_IS_TREE (tree));
g_return_if_fail (row_return != NULL);
g_return_if_fail (col_return != NULL);
/* FIXME it would be nice if it could handle a NULL row_return or
* col_return gracefully. */
if (row_return)
*row_return = -1;
if (col_return)
*col_return = -1;
x += GTK_LAYOUT(tree->priv->table_canvas)->hadjustment->value;
y += GTK_LAYOUT(tree->priv->table_canvas)->vadjustment->value;
e_table_item_compute_location(E_TABLE_ITEM(tree->priv->item), &x, &y, row_return, col_return);
}
/**
* e_tree_get_cell_geometry:
* @tree: The tree.
* @row: The row to get the geometry of.
* @col: The col to get the geometry of.
* @x_return: Returns the x coordinate of the upper right hand corner of the cell with respect to the widget.
* @y_return: Returns the y coordinate of the upper right hand corner of the cell with respect to the widget.
* @width_return: Returns the width of the cell.
* @height_return: Returns the height of the cell.
*
* Computes the data about this cell.
**/
void
e_tree_get_cell_geometry (ETree *tree,
int row, int col,
int *x_return, int *y_return,
int *width_return, int *height_return)
{
g_return_if_fail (tree != NULL);
g_return_if_fail (E_IS_TREE (tree));
g_return_if_fail (row >= 0);
g_return_if_fail (col >= 0);
/* FIXME it would be nice if it could handle a NULL row_return or
* col_return gracefully. */
e_table_item_get_cell_geometry(E_TABLE_ITEM(tree->priv->item), &row, &col, x_return, y_return, width_return, height_return);
if (x_return)
(*x_return) -= GTK_LAYOUT(tree->priv->table_canvas)->hadjustment->value;
if (y_return)
(*y_return) -= GTK_LAYOUT(tree->priv->table_canvas)->vadjustment->value;
}
static void
et_drag_begin (GtkWidget *widget,
GdkDragContext *context,
ETree *et)
{
g_signal_emit (et,
et_signals [TREE_DRAG_BEGIN], 0,
et->priv->drag_row,
et->priv->drag_path,
et->priv->drag_col,
context);
}
static void
et_drag_end (GtkWidget *widget,
GdkDragContext *context,
ETree *et)
{
g_signal_emit (et,
et_signals [TREE_DRAG_END], 0,
et->priv->drag_row,
et->priv->drag_path,
et->priv->drag_col,
context);
}
static void
et_drag_data_get(GtkWidget *widget,
GdkDragContext *context,
GtkSelectionData *selection_data,
guint info,
guint time,
ETree *et)
{
g_signal_emit (et,
et_signals [TREE_DRAG_DATA_GET], 0,
et->priv->drag_row,
et->priv->drag_path,
et->priv->drag_col,
context,
selection_data,
info,
time);
}
static void
et_drag_data_delete(GtkWidget *widget,
GdkDragContext *context,
ETree *et)
{
g_signal_emit (et,
et_signals [TREE_DRAG_DATA_DELETE], 0,
et->priv->drag_row,
et->priv->drag_path,
et->priv->drag_col,
context);
}
static gboolean
do_drag_motion(ETree *et,
GdkDragContext *context,
gint x,
gint y,
guint time)
{
gboolean ret_val = FALSE;
int row, col;
ETreePath path;
GtkWidget *widget;
widget = GTK_WIDGET (et);
e_tree_get_cell_at (et,
x,
y,
&row,
&col);
if (row != et->priv->drop_row && col != et->priv->drop_col) {
g_signal_emit (et,
et_signals [TREE_DRAG_LEAVE], 0,
et->priv->drop_row,
et->priv->drop_path,
et->priv->drop_col,
context,
time);
}
path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
et->priv->drop_row = row;
et->priv->drop_path = path;
et->priv->drop_col = col;
g_signal_emit (et,
et_signals [TREE_DRAG_MOTION], 0,
et->priv->drop_row,
et->priv->drop_path,
et->priv->drop_col,
context,
x,
y,
time,
&ret_val);
return ret_val;
}
static gboolean
scroll_timeout (gpointer data)
{
ETree *et = data;
int dx = 0, dy = 0;
GtkAdjustment *v, *h;
double vvalue, hvalue;
if (et->priv->scroll_direction & ET_SCROLL_DOWN)
dy += 20;
if (et->priv->scroll_direction & ET_SCROLL_UP)
dy -= 20;
if (et->priv->scroll_direction & ET_SCROLL_RIGHT)
dx += 20;
if (et->priv->scroll_direction & ET_SCROLL_LEFT)
dx -= 20;
h = GTK_LAYOUT(et->priv->table_canvas)->hadjustment;
v = GTK_LAYOUT(et->priv->table_canvas)->vadjustment;
hvalue = h->value;
vvalue = v->value;
gtk_adjustment_set_value(h, CLAMP(h->value + dx, h->lower, h->upper - h->page_size));
gtk_adjustment_set_value(v, CLAMP(v->value + dy, v->lower, v->upper - v->page_size));
if (h->value != hvalue ||
v->value != vvalue)
do_drag_motion(et,
et->priv->last_drop_context,
et->priv->last_drop_x,
et->priv->last_drop_y,
et->priv->last_drop_time);
return TRUE;
}
static void
scroll_on (ETree *et, guint scroll_direction)
{
if (et->priv->scroll_idle_id == 0 || scroll_direction != et->priv->scroll_direction) {
if (et->priv->scroll_idle_id != 0)
g_source_remove (et->priv->scroll_idle_id);
et->priv->scroll_direction = scroll_direction;
et->priv->scroll_idle_id = g_timeout_add (100, scroll_timeout, et);
}
}
static void
scroll_off (ETree *et)
{
if (et->priv->scroll_idle_id) {
g_source_remove (et->priv->scroll_idle_id);
et->priv->scroll_idle_id = 0;
}
}
static gboolean
hover_timeout (gpointer data)
{
ETree *et = data;
int x = et->priv->hover_x;
int y = et->priv->hover_y;
int row, col;
ETreePath path;
e_tree_get_cell_at (et,
x,
y,
&row,
&col);
path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
if (path && e_tree_model_node_is_expandable (et->priv->model, path)) {
if (!e_tree_table_adapter_node_is_expanded (et->priv->etta, path)) {
if (e_tree_model_has_save_id (et->priv->model) && e_tree_model_has_get_node_by_id (et->priv->model))
et->priv->expanded_list = g_list_prepend (et->priv->expanded_list, e_tree_model_get_save_id (et->priv->model, path));
e_tree_table_adapter_node_set_expanded (et->priv->etta, path, TRUE);
}
}
return TRUE;
}
static void
hover_on (ETree *et, int x, int y)
{
et->priv->hover_x = x;
et->priv->hover_y = y;
if (et->priv->hover_idle_id != 0)
g_source_remove (et->priv->hover_idle_id);
et->priv->hover_idle_id = g_timeout_add (500, hover_timeout, et);
}
static void
hover_off (ETree *et)
{
if (et->priv->hover_idle_id) {
g_source_remove (et->priv->hover_idle_id);
et->priv->hover_idle_id = 0;
}
}
static void
collapse_drag (ETree *et, ETreePath drop)
{
GList *list;
/* We only want to leave open parents of the node dropped in. Not the node itself. */
if (drop) {
drop = e_tree_model_node_get_parent (et->priv->model, drop);
}
for (list = et->priv->expanded_list; list; list = list->next) {
char *save_id = list->data;
ETreePath path;
path = e_tree_model_get_node_by_id (et->priv->model, save_id);
if (path) {
ETreePath search;
gboolean found = FALSE;
for (search = drop; search; search = e_tree_model_node_get_parent (et->priv->model, search)) {
if (path == search) {
found = TRUE;
break;
}
}
if (!found)
e_tree_table_adapter_node_set_expanded (et->priv->etta, path, FALSE);
}
g_free (save_id);
}
g_list_free (et->priv->expanded_list);
et->priv->expanded_list = NULL;
}
static void
context_destroyed (gpointer data, GObject *ctx)
{
ETree *et = data;
if (et->priv) {
et->priv->last_drop_x = 0;
et->priv->last_drop_y = 0;
et->priv->last_drop_time = 0;
et->priv->last_drop_context = NULL;
collapse_drag (et, NULL);
scroll_off (et);
hover_off (et);
}
g_object_unref (et);
}
static void
context_connect (ETree *et, GdkDragContext *context)
{
if (context == et->priv->last_drop_context)
return;
if (et->priv->last_drop_context)
g_object_weak_unref (G_OBJECT(et->priv->last_drop_context), context_destroyed, et);
else
g_object_ref (et);
g_object_weak_ref (G_OBJECT(context), context_destroyed, et);
}
static void
et_drag_leave(GtkWidget *widget,
GdkDragContext *context,
guint time,
ETree *et)
{
g_signal_emit (et,
et_signals [TREE_DRAG_LEAVE], 0,
et->priv->drop_row,
et->priv->drop_path,
et->priv->drop_col,
context,
time);
et->priv->drop_row = -1;
et->priv->drop_col = -1;
scroll_off (et);
hover_off (et);
}
static gboolean
et_drag_motion(GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
guint time,
ETree *et)
{
int ret_val;
guint direction = 0;
et->priv->last_drop_x = x;
et->priv->last_drop_y = y;
et->priv->last_drop_time = time;
context_connect (et, context);
et->priv->last_drop_context = context;
if (et->priv->hover_idle_id != 0) {
if (abs (et->priv->hover_x - x) > 3 ||
abs (et->priv->hover_y - y) > 3) {
hover_on (et, x, y);
}
} else {
hover_on (et, x, y);
}
ret_val = do_drag_motion (et,
context,
x,
y,
time);
if (y < 20)
direction |= ET_SCROLL_UP;
if (y > widget->allocation.height - 20)
direction |= ET_SCROLL_DOWN;
if (x < 20)
direction |= ET_SCROLL_LEFT;
if (x > widget->allocation.width - 20)
direction |= ET_SCROLL_RIGHT;
if (direction != 0)
scroll_on (et, direction);
else
scroll_off (et);
return ret_val;
}
static gboolean
et_drag_drop(GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
guint time,
ETree *et)
{
gboolean ret_val = FALSE;
int row, col;
ETreePath path;
e_tree_get_cell_at(et,
x,
y,
&row,
&col);
path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
if (row != et->priv->drop_row && col != et->priv->drop_row) {
g_signal_emit (et,
et_signals [TREE_DRAG_LEAVE], 0,
et->priv->drop_row,
et->priv->drop_path,
et->priv->drop_col,
context,
time);
g_signal_emit (et,
et_signals [TREE_DRAG_MOTION], 0,
row,
path,
col,
context,
x,
y,
time,
&ret_val);
}
et->priv->drop_row = row;
et->priv->drop_path = path;
et->priv->drop_col = col;
g_signal_emit (et,
et_signals [TREE_DRAG_DROP], 0,
et->priv->drop_row,
et->priv->drop_path,
et->priv->drop_col,
context,
x,
y,
time,
&ret_val);
et->priv->drop_row = -1;
et->priv->drop_path = NULL;
et->priv->drop_col = -1;
collapse_drag (et, path);
scroll_off (et);
return ret_val;
}
static void
et_drag_data_received(GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
GtkSelectionData *selection_data,
guint info,
guint time,
ETree *et)
{
int row, col;
ETreePath path;
e_tree_get_cell_at(et,
x,
y,
&row,
&col);
path = e_tree_table_adapter_node_at_row(et->priv->etta, row);
g_signal_emit (et,
et_signals [TREE_DRAG_DATA_RECEIVED], 0,
row,
path,
col,
context,
x,
y,
selection_data,
info,
time);
}
static void
e_tree_class_init (ETreeClass *class)
{
GObjectClass *object_class;
GtkWidgetClass *widget_class;
GtkContainerClass *container_class;
object_class = (GObjectClass *) class;
widget_class = (GtkWidgetClass *) class;
container_class = (GtkContainerClass *) class;
parent_class = g_type_class_ref (PARENT_TYPE);
object_class->dispose = et_dispose;
object_class->set_property = et_set_property;
object_class->get_property = et_get_property;
widget_class->grab_focus = et_grab_focus;
widget_class->unrealize = et_unrealize;
widget_class->style_set = et_canvas_style_set;
widget_class->focus = et_focus;
class->cursor_change = NULL;
class->cursor_activated = NULL;
class->selection_change = NULL;
class->double_click = NULL;
class->right_click = NULL;
class->click = NULL;
class->key_press = NULL;
class->start_drag = et_real_start_drag;
class->state_change = NULL;
class->white_space_event = NULL;
class->tree_drag_begin = NULL;
class->tree_drag_end = NULL;
class->tree_drag_data_get = NULL;
class->tree_drag_data_delete = NULL;
class->tree_drag_leave = NULL;
class->tree_drag_motion = NULL;
class->tree_drag_drop = NULL;
class->tree_drag_data_received = NULL;
et_signals [CURSOR_CHANGE] =
g_signal_new ("cursor_change",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, cursor_change),
NULL, NULL,
e_marshal_NONE__INT_POINTER,
G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_POINTER);
et_signals [CURSOR_ACTIVATED] =
g_signal_new ("cursor_activated",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, cursor_activated),
NULL, NULL,
e_marshal_NONE__INT_POINTER,
G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_POINTER);
et_signals [SELECTION_CHANGE] =
g_signal_new ("selection_change",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, selection_change),
NULL, NULL,
e_marshal_NONE__NONE,
G_TYPE_NONE, 0);
et_signals [DOUBLE_CLICK] =
g_signal_new ("double_click",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, double_click),
NULL, NULL,
e_marshal_NONE__INT_POINTER_INT_BOXED,
G_TYPE_NONE, 4, G_TYPE_INT,
G_TYPE_POINTER, G_TYPE_INT, GDK_TYPE_EVENT);
et_signals [RIGHT_CLICK] =
g_signal_new ("right_click",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, right_click),
NULL, NULL,
e_marshal_INT__INT_POINTER_INT_BOXED,
G_TYPE_INT, 4, G_TYPE_INT, G_TYPE_POINTER,
G_TYPE_INT, GDK_TYPE_EVENT);
et_signals [CLICK] =
g_signal_new ("click",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, click),
NULL, NULL,
e_marshal_INT__INT_POINTER_INT_BOXED,
G_TYPE_INT, 4, G_TYPE_INT, G_TYPE_POINTER,
G_TYPE_INT, GDK_TYPE_EVENT);
et_signals [KEY_PRESS] =
g_signal_new ("key_press",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, key_press),
NULL, NULL,
e_marshal_INT__INT_POINTER_INT_BOXED,
G_TYPE_INT, 4, G_TYPE_INT, G_TYPE_POINTER,
G_TYPE_INT, GDK_TYPE_EVENT);
et_signals [START_DRAG] =
g_signal_new ("start_drag",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, start_drag),
NULL, NULL,
e_marshal_NONE__INT_POINTER_INT_BOXED,
G_TYPE_NONE, 4, G_TYPE_INT, G_TYPE_POINTER,
G_TYPE_INT, GDK_TYPE_EVENT);
et_signals [STATE_CHANGE] =
g_signal_new ("state_change",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, state_change),
NULL, NULL,
e_marshal_NONE__NONE,
G_TYPE_NONE, 0);
et_signals [WHITE_SPACE_EVENT] =
g_signal_new ("white_space_event",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, white_space_event),
NULL, NULL,
e_marshal_INT__POINTER,
G_TYPE_INT, 1, GDK_TYPE_EVENT);
et_signals[TREE_DRAG_BEGIN] =
g_signal_new ("tree_drag_begin",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, tree_drag_begin),
NULL, NULL,
e_marshal_NONE__INT_POINTER_INT_BOXED,
G_TYPE_NONE, 4,
G_TYPE_INT,
G_TYPE_POINTER,
G_TYPE_INT,
GDK_TYPE_DRAG_CONTEXT);
et_signals[TREE_DRAG_END] =
g_signal_new ("tree_drag_end",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, tree_drag_end),
NULL, NULL,
e_marshal_NONE__INT_POINTER_INT_BOXED,
G_TYPE_NONE, 4,
G_TYPE_INT,
G_TYPE_POINTER,
G_TYPE_INT,
GDK_TYPE_DRAG_CONTEXT);
et_signals[TREE_DRAG_DATA_GET] =
g_signal_new ("tree_drag_data_get",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, tree_drag_data_get),
NULL, NULL,
e_marshal_NONE__INT_POINTER_INT_OBJECT_BOXED_UINT_UINT,
G_TYPE_NONE, 7,
G_TYPE_INT,
G_TYPE_POINTER,
G_TYPE_INT,
GDK_TYPE_DRAG_CONTEXT,
GTK_TYPE_SELECTION_DATA | G_SIGNAL_TYPE_STATIC_SCOPE,
G_TYPE_UINT,
G_TYPE_UINT);
et_signals[TREE_DRAG_DATA_DELETE] =
g_signal_new ("tree_drag_data_delete",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, tree_drag_data_delete),
NULL, NULL,
e_marshal_NONE__INT_POINTER_INT_OBJECT,
G_TYPE_NONE, 4,
G_TYPE_INT,
G_TYPE_POINTER,
G_TYPE_INT,
GDK_TYPE_DRAG_CONTEXT);
et_signals[TREE_DRAG_LEAVE] =
g_signal_new ("tree_drag_leave",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, tree_drag_leave),
NULL, NULL,
e_marshal_NONE__INT_POINTER_INT_OBJECT_UINT,
G_TYPE_NONE, 5,
G_TYPE_INT,
G_TYPE_POINTER,
G_TYPE_INT,
GDK_TYPE_DRAG_CONTEXT,
G_TYPE_UINT);
et_signals[TREE_DRAG_MOTION] =
g_signal_new ("tree_drag_motion",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, tree_drag_motion),
NULL, NULL,
e_marshal_BOOLEAN__INT_POINTER_INT_OBJECT_INT_INT_UINT,
G_TYPE_BOOLEAN, 7,
G_TYPE_INT,
G_TYPE_POINTER,
G_TYPE_INT,
GDK_TYPE_DRAG_CONTEXT,
G_TYPE_INT,
G_TYPE_INT,
G_TYPE_UINT);
et_signals[TREE_DRAG_DROP] =
g_signal_new ("tree_drag_drop",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, tree_drag_drop),
NULL, NULL,
e_marshal_BOOLEAN__INT_POINTER_INT_OBJECT_INT_INT_UINT,
G_TYPE_BOOLEAN, 7,
G_TYPE_INT,
G_TYPE_POINTER,
G_TYPE_INT,
GDK_TYPE_DRAG_CONTEXT,
G_TYPE_INT,
G_TYPE_INT,
G_TYPE_UINT);
et_signals[TREE_DRAG_DATA_RECEIVED] =
g_signal_new ("tree_drag_data_received",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, tree_drag_data_received),
NULL, NULL,
e_marshal_NONE__INT_POINTER_INT_OBJECT_INT_INT_BOXED_UINT_UINT,
G_TYPE_NONE, 9,
G_TYPE_INT,
G_TYPE_POINTER,
G_TYPE_INT,
GDK_TYPE_DRAG_CONTEXT,
G_TYPE_INT,
G_TYPE_INT,
GTK_TYPE_SELECTION_DATA,
G_TYPE_UINT,
G_TYPE_UINT);
class->set_scroll_adjustments = set_scroll_adjustments;
widget_class->set_scroll_adjustments_signal =
g_signal_new ("set_scroll_adjustments",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ETreeClass, set_scroll_adjustments),
NULL, NULL,
e_marshal_NONE__POINTER_POINTER,
G_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT,
GTK_TYPE_ADJUSTMENT);
g_object_class_install_property (object_class, PROP_LENGTH_THRESHOLD,
g_param_spec_int ("length_threshold",
_( "Length Threshold" ),
_( "Length Threshold" ),
0, G_MAXINT, 0,
G_PARAM_WRITABLE));
g_object_class_install_property (object_class, PROP_HORIZONTAL_DRAW_GRID,
g_param_spec_boolean ("horizontal_draw_grid",
_( "Horizontal Draw Grid" ),
_( "Horizontal Draw Grid" ),
FALSE,
G_PARAM_WRITABLE));
g_object_class_install_property (object_class, PROP_VERTICAL_DRAW_GRID,
g_param_spec_boolean ("vertical_draw_grid",
_( "Vertical Draw Grid" ),
_( "Vertical Draw Grid" ),
FALSE,
G_PARAM_WRITABLE));
g_object_class_install_property (object_class, PROP_DRAW_FOCUS,
g_param_spec_boolean ("drawfocus",
_( "Draw focus" ),
_( "Draw focus" ),
FALSE,
G_PARAM_WRITABLE));
g_object_class_install_property (object_class, PROP_ETTA,
g_param_spec_object ("ETreeTableAdapter",
_( "ETree table adapter" ),
_( "ETree table adapter" ),
E_TREE_TABLE_ADAPTER_TYPE,
G_PARAM_READABLE));
g_object_class_install_property (object_class, PROP_UNIFORM_ROW_HEIGHT,
g_param_spec_boolean ("uniform_row_height",
_( "Uniform row height" ),
_( "Uniform row height" ),
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_ALWAYS_SEARCH,
g_param_spec_boolean ("always_search",
_( "Always search" ),
_( "Always search" ),
FALSE,
G_PARAM_READWRITE));
gtk_widget_class_install_style_property (widget_class,
g_param_spec_boolean ("retro_look",
_("Retro Look"),
_("Draw lines and +/- expanders."),
FALSE,
G_PARAM_READABLE));
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("expander_size",
_("Expander Size"),
_("Size of the expander arrow"),
0,
G_MAXINT,
10,
G_PARAM_READABLE));
gal_a11y_e_tree_init ();
}
E_MAKE_TYPE(e_tree, "ETree", ETree, e_tree_class_init, e_tree_init, PARENT_TYPE)