PKG_CHECK_MODULES([GTKSOURCEVIEW], [gtksourceview-3.0 >= 3.4.2], [],
[PSPP_REQUIRED_PREREQ([gtksourceview 3.0 version 3.4.2 or later (or use --without-gui)])])
- PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.32], [],
- [PSPP_REQUIRED_PREREQ([glib 2.0 version 2.32 or later (or use --without-gui)])])
+ PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.44], [],
+ [PSPP_REQUIRED_PREREQ([glib 2.0 version 2.44 or later (or use --without-gui)])])
AC_ARG_VAR([GLIB_GENMARSHAL])
AC_CHECK_PROGS([GLIB_GENMARSHAL], [glib-genmarshal])
{
CHILD_PROP_0,
CHILD_PROP_RESIZE,
- CHILD_PROP_SHRINK
+ CHILD_PROP_SHRINK,
+ CHILD_PROP_LEFT_ATTACH,
+ CHILD_PROP_TOP_ATTACH
};
enum WidgetSignals
G_MAXINT,
G_PARAM_READABLE));
+
+ gtk_container_class_install_child_property (container_class,
+ CHILD_PROP_LEFT_ATTACH,
+ g_param_spec_int ("left-attach",
+ "Left Attach",
+ "The column number to which the left side of the widget should be attached",
+ 0, 1,
+ 0,
+ G_PARAM_READWRITE));
+
+
+
+ gtk_container_class_install_child_property (container_class,
+ CHILD_PROP_TOP_ATTACH,
+ g_param_spec_int ("top-attach",
+ "Top Attach",
+ "The row number to which the top side of the widget should be attached",
+ 0, 1,
+ 0,
+ G_PARAM_READWRITE));
+
+
+
/**
* GtkPaned:resize:
*
GtkRequisition bottom_right_child_requisition;
gint handle_size;
+ g_print ("Allocate %p %p %p %p\n",
+ xpaned->top_left_child,
+ xpaned->top_right_child,
+ xpaned->bottom_left_child,
+ xpaned->bottom_right_child);
+
/* determine size of handle(s) */
gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
const GValue * value, GParamSpec * pspec)
{
GtkXPaned *xpaned = GTK_XPANED (container);
- gboolean old_value = FALSE;
- gboolean new_value = FALSE;
g_assert (child == xpaned->top_left_child ||
child == xpaned->top_right_child ||
child == xpaned->bottom_left_child ||
child == xpaned->bottom_right_child);
- new_value = g_value_get_boolean (value);
-
+ gint attach = g_value_get_int (value);
switch (property_id)
{
+ case CHILD_PROP_LEFT_ATTACH:
+ g_object_ref (child);
+ gtk_widget_unparent (child);
+ if (attach == 0)
+ {
+ if (child == xpaned->top_right_child)
+ xpaned->top_left_child = child;
+ else if (child == xpaned->bottom_right_child)
+ xpaned->bottom_left_child = child;
+ }
+ else
+ {
+ if (child == xpaned->top_left_child)
+ xpaned->top_right_child = child;
+ else if (child == xpaned->bottom_left_child)
+ xpaned->bottom_right_child = child;
+ }
+ gtk_widget_set_parent (child, GTK_WIDGET (xpaned));
+ g_object_unref (child);
+ break;
+ case CHILD_PROP_TOP_ATTACH:
+ g_object_ref (child);
+ gtk_widget_unparent (child);
+ if (attach == 0)
+ {
+ if (child == xpaned->bottom_right_child)
+ xpaned->top_right_child = child;
+ else if (child == xpaned->bottom_left_child)
+ xpaned->top_left_child = child;
+ }
+ else
+ {
+ if (child == xpaned->top_left_child)
+ xpaned->bottom_left_child = child;
+ else if (child == xpaned->top_right_child)
+ xpaned->bottom_right_child = child;
+ }
+ gtk_widget_set_parent (child, GTK_WIDGET (xpaned));
+ g_object_unref (child);
+ break;
case CHILD_PROP_RESIZE:
- if (child == xpaned->top_left_child)
- {
- old_value = xpaned->top_left_child_resize;
- xpaned->top_left_child_resize = new_value;
- }
- else if (child == xpaned->top_right_child)
- {
- old_value = xpaned->top_right_child_resize;
- xpaned->top_right_child_resize = new_value;
- }
- else if (child == xpaned->bottom_left_child)
- {
- old_value = xpaned->bottom_left_child_resize;
- xpaned->bottom_left_child_resize = new_value;
- }
- else if (child == xpaned->bottom_right_child)
- {
- old_value = xpaned->bottom_right_child_resize;
- xpaned->bottom_right_child_resize = new_value;
- }
+ {
+ gboolean new_value = TRUE;
+
+ if (child == xpaned->top_left_child)
+ {
+ xpaned->top_left_child_resize = new_value;
+ }
+ else if (child == xpaned->top_right_child)
+ {
+ xpaned->top_right_child_resize = new_value;
+ }
+ else if (child == xpaned->bottom_left_child)
+ {
+ xpaned->bottom_left_child_resize = new_value;
+ }
+ else if (child == xpaned->bottom_right_child)
+ {
+ xpaned->bottom_right_child_resize = new_value;
+ }
+ }
break;
-
+
case CHILD_PROP_SHRINK:
- if (child == xpaned->top_left_child)
- {
- old_value = xpaned->top_left_child_shrink;
- xpaned->top_left_child_shrink = new_value;
- }
- else if (child == xpaned->top_right_child)
- {
- old_value = xpaned->top_right_child_shrink;
- xpaned->top_right_child_shrink = new_value;
- }
- else if (child == xpaned->bottom_left_child)
- {
- old_value = xpaned->bottom_left_child_shrink;
- xpaned->bottom_left_child_shrink = new_value;
- }
- else if (child == xpaned->bottom_right_child)
- {
- old_value = xpaned->bottom_right_child_shrink;
- xpaned->bottom_right_child_shrink = new_value;
- }
+ {
+ gboolean new_value = FALSE;
+
+ if (child == xpaned->top_left_child)
+ {
+ xpaned->top_left_child_shrink = new_value;
+ }
+ else if (child == xpaned->top_right_child)
+ {
+ xpaned->top_right_child_shrink = new_value;
+ }
+ else if (child == xpaned->bottom_left_child)
+ {
+ xpaned->bottom_left_child_shrink = new_value;
+ }
+ else if (child == xpaned->bottom_right_child)
+ {
+ xpaned->bottom_right_child_shrink = new_value;
+ }
+ }
break;
default:
GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container,
property_id, pspec);
- old_value = -1; /* quiet gcc */
break;
}
- if (old_value != new_value)
- gtk_widget_queue_resize (GTK_WIDGET (container));
+ gtk_widget_queue_resize (GTK_WIDGET (container));
+ gtk_widget_queue_draw (GTK_WIDGET (container));
}
static void
switch (property_id)
{
+ case CHILD_PROP_TOP_ATTACH:
+ if (child == xpaned->top_left_child)
+ g_value_set_int (value, 0);
+ if (child == xpaned->top_right_child)
+ g_value_set_int (value, 0);
+ if (child == xpaned->bottom_left_child)
+ g_value_set_int (value, 1);
+ if (child == xpaned->bottom_right_child)
+ g_value_set_int (value, 1);
+ break;
+ case CHILD_PROP_LEFT_ATTACH:
+ if (child == xpaned->top_left_child)
+ g_value_set_int (value, 0);
+ if (child == xpaned->bottom_left_child)
+ g_value_set_int (value, 0);
+ if (child == xpaned->top_right_child)
+ g_value_set_int (value, 1);
+ if (child == xpaned->bottom_right_child)
+ g_value_set_int (value, 1);
+ break;
case CHILD_PROP_RESIZE:
if (child == xpaned->top_left_child)
g_value_set_boolean (value, xpaned->top_left_child_resize);
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Free Software Foundation, Inc.
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
#include "gettext.h"
#define _(msgid) gettext (msgid)
+#define N_(msgid) (msgid)
+
+/* This should follow the definition in Gtk */
+typedef struct
+{
+ int value;
+ const char *name;
+ const char *label;
+} GEnumValue;
+
+const GEnumValue align[] =
+ {
+ {ALIGN_LEFT, "left", N_("Left")},
+ {ALIGN_RIGHT, "right", N_("Right")},
+ {ALIGN_CENTRE, "center", N_("Center")},
+ {0,0,0}
+ };
+
+const GEnumValue measure[] =
+ {
+ {MEASURE_NOMINAL, "nominal", N_("Nominal")},
+ {MEASURE_ORDINAL, "ordinal", N_("Ordinal")},
+ {MEASURE_SCALE, "scale", N_("Scale")},
+ {0,0,0}
+ };
+
+const GEnumValue role[] =
+ {
+ {ROLE_INPUT, "input", N_("Input")},
+ {ROLE_TARGET, "output", N_("Output")},
+ {ROLE_BOTH, "both", N_("Both")},
+ {ROLE_NONE, "none", N_("None")},
+ {ROLE_PARTITION, "partition", N_("Partition")},
+ {ROLE_SPLIT, "split", N_("Split")},
+ {0,0,0}
+ };
/* A variable. */
struct variable
const char *
measure_to_string (enum measure m)
{
- switch (m)
- {
- case MEASURE_NOMINAL:
- return _("Nominal");
-
- case MEASURE_ORDINAL:
- return _("Ordinal");
-
- case MEASURE_SCALE:
- return _("Scale");
-
- default:
- return "Invalid";
- }
+ assert (m == measure[m].value);
+ return gettext (measure[m].label);
}
/* Returns a string version of measurement level M, for use in PSPP command
/* Returns a string version of ROLE, for display to a user. */
const char *
-var_role_to_string (enum var_role role)
+var_role_to_string (enum var_role r)
{
- switch (role)
- {
- case ROLE_INPUT:
- return _("Input");
-
- case ROLE_TARGET:
- return _("Output");
-
- case ROLE_BOTH:
- return _("Both");
-
- case ROLE_NONE:
- return _("None");
-
- case ROLE_PARTITION:
- return _("Partition");
-
- case ROLE_SPLIT:
- return _("Split");
-
- default:
- return "Invalid";
- }
+ assert (r == role[r].value);
+ return gettext (role[r].label);
}
/* Returns a string version of ROLE, for use in PSPP comamnd syntax. */
const char *
alignment_to_string (enum alignment a)
{
- switch (a)
- {
- case ALIGN_LEFT:
- return _("Left");
-
- case ALIGN_RIGHT:
- return _("Right");
-
- case ALIGN_CENTRE:
- return _("Center");
-
- default:
- return "Invalid";
- }
+ assert (a == align[a].value);
+ return gettext (align[a].label);
}
/* Returns a string version of alignment A, for use in PSPP command syntax. */
src/ui/gui/marshaller-list \
src/ui/gui/pspplogo.svg
+src_ui_gui_psppire_CPPFLAGS=
if HAVE_GUI
bin_PROGRAMS += src/ui/gui/psppire
$(top_srcdir)/src/ui/gui/psppire.gtkrc
src_ui_gui_psppire_SOURCES = \
- src/ui/gui/pspp-sheet-private.h \
- src/ui/gui/pspp-sheet-selection.c \
- src/ui/gui/pspp-sheet-selection.h \
- src/ui/gui/pspp-sheet-view-column.c \
- src/ui/gui/pspp-sheet-view-column.h \
- src/ui/gui/pspp-sheet-view.c \
- src/ui/gui/pspp-sheet-view.h \
- src/ui/gui/pspp-widget-facade.c \
- src/ui/gui/pspp-widget-facade.h \
- src/ui/gui/psppire-button-editable.c \
- src/ui/gui/psppire-button-editable.h \
- src/ui/gui/psppire-cell-renderer-button.c \
- src/ui/gui/psppire-cell-renderer-button.h \
src/ui/gui/psppire-dialog.c \
src/ui/gui/psppire-keypad.c \
src/ui/gui/psppire-selector.c \
src/ui/gui/psppire-conf.h \
src/ui/gui/psppire-data-editor.c \
src/ui/gui/psppire-data-editor.h \
- src/ui/gui/psppire-data-sheet.c \
- src/ui/gui/psppire-data-sheet.h \
src/ui/gui/psppire-data-store.c \
src/ui/gui/psppire-data-store.h \
src/ui/gui/psppire-data-window.c \
src/ui/gui/psppire-value-entry.h \
src/ui/gui/psppire-var-ptr.c \
src/ui/gui/psppire-var-ptr.h \
- src/ui/gui/psppire-var-sheet.c \
- src/ui/gui/psppire-var-sheet.h \
+ src/ui/gui/psppire-var-sheet-header.h \
+ src/ui/gui/psppire-var-sheet-header.c \
src/ui/gui/psppire-window.c \
src/ui/gui/psppire-window.h \
src/ui/gui/psppire-window-base.c \
src/ui/gui/var-display.h \
src/ui/gui/var-type-dialog.c \
src/ui/gui/var-type-dialog.h \
+ src/ui/gui/value-variant.c \
+ src/ui/gui/value-variant.h \
src/ui/gui/widget-io.c \
src/ui/gui/widget-io.h \
src/ui/gui/widgets.c \
BUILT_SOURCES += src/ui/gui/psppire-marshal.c src/ui/gui/psppire-marshal.h src/ui/gui/resources.c
CLEANFILES += src/ui/gui/psppire-marshal.c src/ui/gui/psppire-marshal.h \
- src/ui/gui/resources.c $(nodist_src_ui_gui_psppire_DATA)
+ src/ui/gui/resources.c $(nodist_src_ui_gui_psppire_DATA)
+
+include $(top_srcdir)/src/ui/gui/efficient-sheet.mk
endif HAVE_GUI
#ensure the installcheck passes even if there is no X server available
DISPLAY=/invalid/port $(MAKE) $(AM_MAKEFLAGS) installcheck-binPROGRAMS
# <gtk/gtk.h> wrapper
-src_ui_gui_psppire_CPPFLAGS = $(AM_CPPFLAGS) -Isrc/ui/gui/include
+src_ui_gui_psppire_CPPFLAGS += $(AM_CPPFLAGS) -Isrc/ui/gui/include
BUILT_SOURCES += src/ui/gui/include/gtk/gtk.h
src/ui/gui/include/gtk/gtk.h: src/ui/gui/include/gtk/gtk.in.h
@$(MKDIR_P) src/ui/gui/include/gtk
--- /dev/null
+src_ui_gui_psppire_SOURCES += \
+ src/ui/gui/efficient-sheet/jmd-axis-model.c \
+ src/ui/gui/efficient-sheet/jmd-constraint.c \
+ src/ui/gui/efficient-sheet/jmd-sheet.c \
+ src/ui/gui/efficient-sheet/jmd-sheet-axis.c \
+ src/ui/gui/efficient-sheet/jmd-sheet-body.c \
+ src/ui/gui/efficient-sheet/jmd-sheet-single.c \
+ src/ui/gui/efficient-sheet/jmd-datum.c \
+ src/ui/gui/efficient-sheet/jmd-cell.c
+
+
+nodist_src_ui_gui_psppire_SOURCES += \
+ src/ui/gui/efficient-sheet/jmd-marshaller.c \
+ src/ui/gui/efficient-sheet/jmd-marshaller.h
+
+src_ui_gui_psppire_CPPFLAGS+=-Isrc/ui/gui/efficient-sheet
+
+
+
+BUILT_SOURCES += \
+ src/ui/gui/efficient-sheet/jmd-marshaller.c \
+ src/ui/gui/efficient-sheet/jmd-marshaller.h
+
+src/ui/gui/efficient-sheet/jmd-marshaller.c: src/ui/gui/efficient-sheet/marshall-list
+ glib-genmarshal --body --prefix=jmd_cclosure_marshal $< > $@
+
+src/ui/gui/efficient-sheet/jmd-marshaller.h: src/ui/gui/efficient-sheet/marshall-list
+ glib-genmarshal --header --prefix=jmd_cclosure_marshal $< > $@
+
#include "ui/gui/dict-display.h"
#include "ui/gui/find-dialog.h"
#include "ui/gui/helper.h"
-#include "ui/gui/psppire-data-sheet.h"
#include "ui/gui/psppire-data-store.h"
#include "ui/gui/psppire-data-window.h"
#include "ui/gui/psppire-dialog.h"
static void
do_find (GObject *obj, const struct find_dialog *fd)
{
- PsppireDataSheet *data_sheet;
casenumber x = -1;
gint column = -1;
glong row;
- data_sheet = psppire_data_editor_get_active_data_sheet (fd->de->data_editor);
- row = psppire_data_sheet_get_selected_case (data_sheet);
+
+ row = 10;
find_value (fd, row, &x, &column);
gtk_notebook_set_current_page (GTK_NOTEBOOK (fd->de->data_editor),
PSPPIRE_DATA_EDITOR_DATA_VIEW);
- psppire_data_sheet_goto_case (data_sheet, x);
- psppire_data_sheet_goto_variable (data_sheet, column);
}
}
/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2007, 2011, 2012 Free Software Foundation
+ Copyright (C) 2007, 2011, 2012, 2016 Free Software Foundation
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
#include "psppire-dialog.h"
#include "psppire-data-window.h"
#include "psppire-data-store.h"
+#include "ui/gui/efficient-sheet/jmd-sheet.h"
static void
-refresh (PsppireDataSheet *ds, GtkBuilder *xml)
+refresh (JmdSheet *ds, GtkBuilder *xml)
{
- PsppireDataStore *data_store = psppire_data_sheet_get_data_store (ds);
- casenumber case_count ;
-
GtkWidget *case_num_entry = get_widget_assert (xml, "goto-case-case-num-entry");
-
- case_count = psppire_data_store_get_case_count (data_store);
+ casenumber case_count = gtk_tree_model_iter_n_children (ds->data_model, NULL);
gtk_spin_button_set_range (GTK_SPIN_BUTTON (case_num_entry), 1, case_count);
}
void
-goto_case_dialog (PsppireDataSheet *ds)
+goto_case_dialog (JmdSheet *ds)
{
GtkWindow *top_level;
gint response;
response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
- if ( response == PSPPIRE_RESPONSE_GOTO )
+ if (response == PSPPIRE_RESPONSE_GOTO)
{
- PsppireDataStore *data_store = psppire_data_sheet_get_data_store (ds);
- glong case_num;
GtkWidget *case_num_entry =
- get_widget_assert (xml, "goto-case-case-num-entry");
-
- case_num = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (case_num_entry))
- - FIRST_CASE_NUMBER ;
-
- if (case_num >= 0
- && case_num < psppire_data_store_get_case_count (data_store))
- psppire_data_sheet_goto_case (ds, case_num);
+ get_widget_assert (xml, "goto-case-case-num-entry");
+
+ glong case_num =
+ gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (case_num_entry))
+ - FIRST_CASE_NUMBER ;
+
+ if (case_num >= 0 &&
+ case_num < gtk_tree_model_iter_n_children (ds->data_model, NULL))
+ {
+ jmd_sheet_scroll_to (ds, -1, case_num);
+ jmd_sheet_set_active_cell (ds, -1, case_num, 0);
+ }
}
}
#ifndef __GOTO_CASE_DIALOG_H
#define __GOTO_CASE_DIALOG_H
-#include "psppire-data-sheet.h"
+#include "ui/gui/efficient-sheet/jmd-sheet.h"
-void goto_case_dialog (PsppireDataSheet *ds);
+
+void goto_case_dialog (JmdSheet *ds);
#endif
VOID:OBJECT,OBJECT
VOID:POINTER,INT,INT
VOID:INT,UINT,POINTER
+VOID:UINT,UINT,UINT
+++ /dev/null
- /* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2011, 2012, 2013 Free Software Foundation, Inc.
-
- 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/>. */
-
-/* gtktreeprivate.h
- * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * 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.
- */
-
-#ifndef __GTK_TREE_PRIVATE_H__
-#define __GTK_TREE_PRIVATE_H__
-
-
-#include <gtk/gtk.h>
-#include "libpspp/range-tower.h"
-#include "ui/gui/pspp-sheet-view.h"
-#include "ui/gui/pspp-sheet-view-column.h"
-
-#define TREE_VIEW_DRAG_WIDTH 6
-
-typedef enum
-{
- PSPP_SHEET_VIEW_IN_COLUMN_RESIZE = 1 << 2,
- PSPP_SHEET_VIEW_HEADERS_VISIBLE = 1 << 4,
- PSPP_SHEET_VIEW_DRAW_KEYFOCUS = 1 << 5,
- PSPP_SHEET_VIEW_MODEL_SETUP = 1 << 6,
- PSPP_SHEET_VIEW_IN_COLUMN_DRAG = 1 << 7
-} PsppSheetViewFlags;
-
-enum
-{
- DRAG_COLUMN_WINDOW_STATE_UNSET = 0,
- DRAG_COLUMN_WINDOW_STATE_ORIGINAL = 1,
- DRAG_COLUMN_WINDOW_STATE_ARROW = 2,
- DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT = 3,
- DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT = 4
-};
-
-enum
-{
- RUBBER_BAND_OFF = 0,
- RUBBER_BAND_MAYBE_START = 1,
- RUBBER_BAND_ACTIVE = 2
-};
-
-#define PSPP_SHEET_VIEW_SET_FLAG(tree_view, flag) G_STMT_START{ (tree_view->priv->flags|=flag); }G_STMT_END
-#define PSPP_SHEET_VIEW_UNSET_FLAG(tree_view, flag) G_STMT_START{ (tree_view->priv->flags&=~(flag)); }G_STMT_END
-#define PSPP_SHEET_VIEW_FLAG_SET(tree_view, flag) ((tree_view->priv->flags&flag)==flag)
-#define TREE_VIEW_HEADER_HEIGHT(tree_view) (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_HEADERS_VISIBLE)?tree_view->priv->header_height:0)
-#define TREE_VIEW_COLUMN_REQUESTED_WIDTH(column) (CLAMP (column->requested_width, (column->min_width!=-1)?column->min_width:column->requested_width, (column->max_width!=-1)?column->max_width:column->requested_width))
-
- /* This lovely little value is used to determine how far away from the title bar
- * you can move the mouse and still have a column drag work.
- */
-#define TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER(tree_view) (10*TREE_VIEW_HEADER_HEIGHT(tree_view))
-
-typedef struct _PsppSheetViewColumnReorder PsppSheetViewColumnReorder;
-struct _PsppSheetViewColumnReorder
-{
- gint left_align;
- gint right_align;
- PsppSheetViewColumn *left_column;
- PsppSheetViewColumn *right_column;
-};
-
-struct _PsppSheetViewPrivate
-{
- GtkTreeModel *model;
-
- guint flags;
- /* tree information */
- gint row_count;
- struct range_tower *selected;
-
- /* Container info */
- GList *children;
- gint width;
- gint height;
-
- /* Adjustments */
- GtkAdjustment *hadjustment;
- GtkAdjustment *vadjustment;
-
- /* Sub windows */
- GdkWindow *bin_window;
- GdkWindow *header_window;
-
- /* Scroll position state keeping */
- GtkTreeRowReference *top_row;
- gint top_row_dy;
- /* dy == y pos of top_row + top_row_dy */
- /* we cache it for simplicity of the code */
- gint dy;
-
- guint presize_handler_timer;
- guint validate_rows_timer;
- guint scroll_sync_timer;
-
- /* Indentation and expander layout */
- gint expander_size;
-
- /* Key navigation (focus), selection */
- gint cursor_offset;
-
- GtkTreeRowReference *anchor;
- GtkTreeRowReference *cursor;
-
- PsppSheetViewColumn *focus_column;
-
- /* Current pressed node, previously pressed, prelight */
- gint pressed_button;
- gint press_start_x;
- gint press_start_y;
- gint press_start_node;
-
- gint event_last_x;
- gint event_last_y;
-
- guint last_button_time;
- gint last_button_x;
- gint last_button_y;
-
- int prelight_node;
-
- /* Cell Editing */
- PsppSheetViewColumn *edited_column;
- gint edited_row;
-
- /* Selection information */
- PsppSheetSelection *selection;
-
- /* Header information */
- gint n_columns;
- GList *columns;
- gint header_height;
- gint n_selected_columns;
-
- PsppSheetViewColumnDropFunc column_drop_func;
- gpointer column_drop_func_data;
- GDestroyNotify column_drop_func_data_destroy;
- GList *column_drag_info;
- PsppSheetViewColumnReorder *cur_reorder;
-
- /* Interactive Header reordering */
- GdkWindow *drag_window;
- GdkWindow *drag_highlight_window;
- PsppSheetViewColumn *drag_column;
- gint drag_column_x;
-
- /* Interactive Header Resizing */
- gint drag_pos;
- gint x_drag;
-
- /* Non-interactive Header Resizing, expand flag support */
- gint prev_width;
-
- /* ATK Hack */
- PsppSheetDestroyCountFunc destroy_count_func;
- gpointer destroy_count_data;
- GDestroyNotify destroy_count_destroy;
-
- /* Scroll timeout (e.g. during dnd, rubber banding) */
- guint scroll_timeout;
-
- /* Row drag-and-drop */
- GtkTreeRowReference *drag_dest_row;
- PsppSheetViewDropPosition drag_dest_pos;
- guint open_dest_timeout;
-
- /* Rubber banding */
- gint rubber_band_status;
- gint rubber_band_x;
- gint rubber_band_y;
- gint rubber_band_shift;
- gint rubber_band_ctrl;
-
- int rubber_band_start_node;
-
- int rubber_band_end_node;
-
- /* Rectangular selection. */
- PsppSheetViewColumn *anchor_column; /* XXX needs to be a weak pointer? */
-
- /* fixed height */
- gint fixed_height;
- gboolean fixed_height_set;
-
- /* Scroll-to functionality when unrealized */
- GtkTreeRowReference *scroll_to_path;
- PsppSheetViewColumn *scroll_to_column;
- gfloat scroll_to_row_align;
- gfloat scroll_to_col_align;
-
- /* Interactive search */
- gint selected_iter;
- gint search_column;
- PsppSheetViewSearchPositionFunc search_position_func;
- PsppSheetViewSearchEqualFunc search_equal_func;
- gpointer search_user_data;
- GDestroyNotify search_destroy;
- gpointer search_position_user_data;
- GDestroyNotify search_position_destroy;
- GtkWidget *search_window;
- GtkWidget *search_entry;
- guint search_entry_changed_id;
- guint typeselect_flush_timeout;
-
- /* Grid and tree lines */
- PsppSheetViewGridLines grid_lines;
-
- /* Special cells. */
- PsppSheetViewSpecialCells special_cells;
-
- /* Tooltip support */
- gint tooltip_column;
-
- /* Cached style for button facades in columns. */
- GtkStyle *button_style;
-
- /* Here comes the bitfield */
- guint scroll_to_use_align : 1;
-
- guint reorderable : 1;
- guint header_has_focus : 1;
- guint drag_column_window_state : 3;
- /* hint to display rows in alternating colors */
- guint has_rules : 1;
-
- /* for DnD */
- guint empty_view_drop : 1;
-
- guint init_hadjust_value : 1;
-
- guint in_top_row_to_dy : 1;
-
- /* interactive search */
- guint enable_search : 1;
- guint disable_popdown : 1;
- guint search_custom_entry_set : 1;
-
- guint hover_selection : 1;
- guint imcontext_changed : 1;
-
- guint rubber_banding_enable : 1;
-
- guint in_grab : 1;
-
- guint post_validation_flag : 1;
-
- /* Whether our key press handler is to avoid sending an unhandled binding to the search entry */
-
- guint search_entry_avoid_unhandled_binding : 1;
- /* GtkScrollablePolicy needs to be checked when
- * driving the scrollable adjustment values */
- guint hscroll_policy : 1;
- guint vscroll_policy : 1;
-
- /* For optimisation of size allocate requests */
- guint resized : 1;
- };
-
-#ifdef __GNUC__
-
-#define TREE_VIEW_INTERNAL_ASSERT(expr, ret) G_STMT_START{ \
- if (!(expr)) \
- { \
- g_log (G_LOG_DOMAIN, \
- G_LOG_LEVEL_CRITICAL, \
- "%s (%s): assertion `%s' failed.\n" \
- "There is a disparity between the internal view of the PsppSheetView,\n" \
- "and the GtkTreeModel. This generally means that the model has changed\n"\
- "without letting the view know. Any display from now on is likely to\n" \
- "be incorrect.\n", \
- G_STRLOC, \
- G_STRFUNC, \
- #expr); \
- return ret; \
- }; }G_STMT_END
-
-#define TREE_VIEW_INTERNAL_ASSERT_VOID(expr) G_STMT_START{ \
- if (!(expr)) \
- { \
- g_log (G_LOG_DOMAIN, \
- G_LOG_LEVEL_CRITICAL, \
- "%s (%s): assertion `%s' failed.\n" \
- "There is a disparity between the internal view of the PsppSheetView,\n" \
- "and the GtkTreeModel. This generally means that the model has changed\n"\
- "without letting the view know. Any display from now on is likely to\n" \
- "be incorrect.\n", \
- G_STRLOC, \
- G_STRFUNC, \
- #expr); \
- return; \
- }; }G_STMT_END
-
-#else
-
-#define TREE_VIEW_INTERNAL_ASSERT(expr, ret) G_STMT_START{ \
- if (!(expr)) \
- { \
- g_log (G_LOG_DOMAIN, \
- G_LOG_LEVEL_CRITICAL, \
- "file %s: line %d: assertion `%s' failed.\n" \
- "There is a disparity between the internal view of the PsppSheetView,\n" \
- "and the GtkTreeModel. This generally means that the model has changed\n"\
- "without letting the view know. Any display from now on is likely to\n" \
- "be incorrect.\n", \
- __FILE__, \
- __LINE__, \
- #expr); \
- return ret; \
- }; }G_STMT_END
-
-#define TREE_VIEW_INTERNAL_ASSERT_VOID(expr) G_STMT_START{ \
- if (!(expr)) \
- { \
- g_log (G_LOG_DOMAIN, \
- G_LOG_LEVEL_CRITICAL, \
- "file %s: line %d: assertion '%s' failed.\n" \
- "There is a disparity between the internal view of the PsppSheetView,\n" \
- "and the GtkTreeModel. This generally means that the model has changed\n"\
- "without letting the view know. Any display from now on is likely to\n" \
- "be incorrect.\n", \
- __FILE__, \
- __LINE__, \
- #expr); \
- return; \
- }; }G_STMT_END
-#endif
-
-
-/* functions that shouldn't be exported */
-void _pspp_sheet_selection_internal_select_node (PsppSheetSelection *selection,
- int node,
- GtkTreePath *path,
- PsppSheetSelectMode mode,
- gboolean override_browse_mode);
-void _pspp_sheet_selection_emit_changed (PsppSheetSelection *selection);
-void _pspp_sheet_view_find_node (PsppSheetView *tree_view,
- GtkTreePath *path,
- int *node);
-GtkTreePath *_pspp_sheet_view_find_path (PsppSheetView *tree_view,
- int node);
-void _pspp_sheet_view_child_move_resize (PsppSheetView *tree_view,
- GtkWidget *widget,
- gint x,
- gint y,
- gint width,
- gint height);
-void _pspp_sheet_view_queue_draw_node (PsppSheetView *tree_view,
- int node,
- const GdkRectangle *clip_rect);
-
-void _pspp_sheet_view_column_realize_button (PsppSheetViewColumn *column);
-void _pspp_sheet_view_column_unrealize_button (PsppSheetViewColumn *column);
-void _pspp_sheet_view_column_set_tree_view (PsppSheetViewColumn *column,
- PsppSheetView *tree_view);
-void _pspp_sheet_view_column_unset_model (PsppSheetViewColumn *column,
- GtkTreeModel *old_model);
-void _pspp_sheet_view_column_unset_tree_view (PsppSheetViewColumn *column);
-void _pspp_sheet_view_column_set_width (PsppSheetViewColumn *column,
- gint width);
-void _pspp_sheet_view_column_start_drag (PsppSheetView *tree_view,
- PsppSheetViewColumn *column);
-gboolean _pspp_sheet_view_column_cell_event (PsppSheetViewColumn *tree_column,
- GtkCellEditable **editable_widget,
- GdkEvent *event,
- gchar *path_string,
- const GdkRectangle *background_area,
- const GdkRectangle *cell_area,
- guint flags);
-void _pspp_sheet_view_column_start_editing (PsppSheetViewColumn *tree_column,
- GtkCellEditable *editable_widget);
-void _pspp_sheet_view_column_stop_editing (PsppSheetViewColumn *tree_column);
-void _pspp_sheet_view_install_mark_rows_col_dirty (PsppSheetView *tree_view);
-void _pspp_sheet_view_column_autosize (PsppSheetView *tree_view,
- PsppSheetViewColumn *column);
-
-gboolean _pspp_sheet_view_column_has_editable_cell (PsppSheetViewColumn *column);
-GtkCellRenderer *_pspp_sheet_view_column_get_edited_cell (PsppSheetViewColumn *column);
-gint _pspp_sheet_view_column_count_special_cells (PsppSheetViewColumn *column);
-GtkCellRenderer *_pspp_sheet_view_column_get_cell_at_pos (PsppSheetViewColumn *column,
- gint x);
-
-PsppSheetSelection* _pspp_sheet_selection_new (void);
-PsppSheetSelection* _pspp_sheet_selection_new_with_tree_view (PsppSheetView *tree_view);
-void _pspp_sheet_selection_set_tree_view (PsppSheetSelection *selection,
- PsppSheetView *tree_view);
-
-void _pspp_sheet_view_column_cell_render (PsppSheetViewColumn *tree_column,
- cairo_t *cr,
- const GdkRectangle *background_area,
- const GdkRectangle *cell_area,
- guint flags);
-void _pspp_sheet_view_column_get_focus_area (PsppSheetViewColumn *tree_column,
- const GdkRectangle *background_area,
- const GdkRectangle *cell_area,
- GdkRectangle *focus_area);
-gboolean _pspp_sheet_view_column_cell_focus (PsppSheetViewColumn *tree_column,
- gint direction,
- gboolean left,
- gboolean right);
-void _pspp_sheet_view_column_cell_draw_focus (PsppSheetViewColumn *tree_column,
- cairo_t *cr,
- const GdkRectangle *background_area,
- const GdkRectangle *cell_area,
- guint flags);
-void _pspp_sheet_view_column_cell_set_dirty (PsppSheetViewColumn *tree_column);
-void _pspp_sheet_view_column_get_neighbor_sizes (PsppSheetViewColumn *column,
- GtkCellRenderer *cell,
- gint *left,
- gint *right);
-
-gboolean pspp_sheet_view_node_is_selected (PsppSheetView *tree_view,
- int node);
-void pspp_sheet_view_node_select (PsppSheetView *tree_view,
- int node);
-void pspp_sheet_view_node_unselect (PsppSheetView *tree_view,
- int node);
-
-gint
-pspp_sheet_view_node_next (PsppSheetView *tree_view,
- gint node);
-gint
-pspp_sheet_view_node_prev (PsppSheetView *tree_view,
- gint node);
-
-#endif /* __GTK_TREE_PRIVATE_H__ */
-
+++ /dev/null
-/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2011, 2012, 2013 Free Software Foundation, Inc.
-
- 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/>. */
-
-/* gtktreeselection.h
- * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * 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 "ui/gui/pspp-sheet-private.h"
-
-#include <gtk/gtk.h>
-#include <string.h>
-
-#include "ui/gui/pspp-sheet-selection.h"
-
-#include "libpspp/range-set.h"
-
-static void pspp_sheet_selection_finalize (GObject *object);
-static gint pspp_sheet_selection_real_select_all (PsppSheetSelection *selection);
-static gint pspp_sheet_selection_real_unselect_all (PsppSheetSelection *selection);
-static gint pspp_sheet_selection_real_select_node (PsppSheetSelection *selection,
- int node,
- gboolean select);
-
-enum
-{
- CHANGED,
- LAST_SIGNAL
-};
-
-static guint tree_selection_signals [LAST_SIGNAL] = { 0 };
-
-G_DEFINE_TYPE (PsppSheetSelection, pspp_sheet_selection, G_TYPE_OBJECT)
-
-static void
-pspp_sheet_selection_class_init (PsppSheetSelectionClass *class)
-{
- GObjectClass *object_class;
-
- object_class = (GObjectClass*) class;
-
- object_class->finalize = pspp_sheet_selection_finalize;
- class->changed = NULL;
-
- tree_selection_signals[CHANGED] =
- g_signal_new ("changed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (PsppSheetSelectionClass, changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-}
-
-static void
-pspp_sheet_selection_init (PsppSheetSelection *selection)
-{
- selection->type = PSPP_SHEET_SELECTION_SINGLE;
-}
-
-static void
-pspp_sheet_selection_finalize (GObject *object)
-{
- G_OBJECT_CLASS (pspp_sheet_selection_parent_class)->finalize (object);
-}
-
-/**
- * _pspp_sheet_selection_new:
- *
- * Creates a new #PsppSheetSelection object. This function should not be invoked,
- * as each #PsppSheetView will create its own #PsppSheetSelection.
- *
- * Return value: A newly created #PsppSheetSelection object.
- **/
-PsppSheetSelection*
-_pspp_sheet_selection_new (void)
-{
- PsppSheetSelection *selection;
-
- selection = g_object_new (PSPP_TYPE_SHEET_SELECTION, NULL);
-
- return selection;
-}
-
-/**
- * _pspp_sheet_selection_new_with_tree_view:
- * @tree_view: The #PsppSheetView.
- *
- * Creates a new #PsppSheetSelection object. This function should not be invoked,
- * as each #PsppSheetView will create its own #PsppSheetSelection.
- *
- * Return value: A newly created #PsppSheetSelection object.
- **/
-PsppSheetSelection*
-_pspp_sheet_selection_new_with_tree_view (PsppSheetView *tree_view)
-{
- PsppSheetSelection *selection;
-
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
- selection = _pspp_sheet_selection_new ();
- _pspp_sheet_selection_set_tree_view (selection, tree_view);
-
- return selection;
-}
-
-/**
- * _pspp_sheet_selection_set_tree_view:
- * @selection: A #PsppSheetSelection.
- * @tree_view: The #PsppSheetView.
- *
- * Sets the #PsppSheetView of @selection. This function should not be invoked, as
- * it is used internally by #PsppSheetView.
- **/
-void
-_pspp_sheet_selection_set_tree_view (PsppSheetSelection *selection,
- PsppSheetView *tree_view)
-{
- g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
- if (tree_view != NULL)
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- selection->tree_view = tree_view;
-}
-
-/**
- * pspp_sheet_selection_set_mode:
- * @selection: A #PsppSheetSelection.
- * @type: The selection mode
- *
- * Sets the selection mode of the @selection. If the previous type was
- * #PSPP_SHEET_SELECTION_MULTIPLE or #PSPP_SHEET_SELECTION_RECTANGLE, then the
- * anchor is kept selected, if it was previously selected.
- **/
-void
-pspp_sheet_selection_set_mode (PsppSheetSelection *selection,
- PsppSheetSelectionMode type)
-{
- g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
-
- if (selection->type == type)
- return;
-
- if (type == PSPP_SHEET_SELECTION_NONE)
- {
- pspp_sheet_selection_unselect_all (selection);
-
- gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
- selection->tree_view->priv->anchor = NULL;
- }
- else if (type == PSPP_SHEET_SELECTION_SINGLE ||
- type == PSPP_SHEET_SELECTION_BROWSE)
- {
- int node = -1;
- gint selected = FALSE;
- GtkTreePath *anchor_path = NULL;
-
- if (selection->tree_view->priv->anchor)
- {
- anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
-
- if (anchor_path)
- {
- _pspp_sheet_view_find_node (selection->tree_view,
- anchor_path,
- &node);
-
- if (node >= 0 && pspp_sheet_view_node_is_selected (selection->tree_view, node))
- selected = TRUE;
- }
- }
-
- /* We do this so that we unconditionally unset all rows
- */
- pspp_sheet_selection_unselect_all (selection);
-
- if (node >= 0 && selected)
- _pspp_sheet_selection_internal_select_node (selection,
- node,
- anchor_path,
- 0,
- FALSE);
- if (anchor_path)
- gtk_tree_path_free (anchor_path);
- }
-
- /* XXX unselect all columns when switching to/from rectangular selection? */
-
- selection->type = type;
-}
-
-/**
- * pspp_sheet_selection_get_mode:
- * @selection: a #PsppSheetSelection
- *
- * Gets the selection mode for @selection. See
- * pspp_sheet_selection_set_mode().
- *
- * Return value: the current selection mode
- **/
-PsppSheetSelectionMode
-pspp_sheet_selection_get_mode (PsppSheetSelection *selection)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), PSPP_SHEET_SELECTION_SINGLE);
-
- return selection->type;
-}
-
-/**
- * pspp_sheet_selection_get_tree_view:
- * @selection: A #PsppSheetSelection
- *
- * Returns the tree view associated with @selection.
- *
- * Return value: A #PsppSheetView
- **/
-PsppSheetView *
-pspp_sheet_selection_get_tree_view (PsppSheetSelection *selection)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), NULL);
-
- return selection->tree_view;
-}
-
-/**
- * pspp_sheet_selection_get_selected:
- * @selection: A #PsppSheetSelection.
- * @model: (out) (allow-none): A pointer to set to the #GtkTreeModel, or NULL.
- * @iter: (allow-none): The #GtkTreeIter, or NULL.
- *
- * Sets @iter to the currently selected node if @selection is set to
- * #PSPP_SHEET_SELECTION_SINGLE or #PSPP_SHEET_SELECTION_BROWSE. @iter may be
- * NULL if you just want to test if @selection has any selected nodes. @model
- * is filled with the current model as a convenience. This function will not
- * work if @selection's mode is #PSPP_SHEET_SELECTION_MULTIPLE or
- * #PSPP_SHEET_SELECTION_RECTANGLE.
- *
- * Return value: TRUE, if there is a selected node.
- **/
-gboolean
-pspp_sheet_selection_get_selected (PsppSheetSelection *selection,
- GtkTreeModel **model,
- GtkTreeIter *iter)
-{
- int node;
- GtkTreePath *anchor_path;
- gboolean retval;
-
- g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), FALSE);
- g_return_val_if_fail (selection->type != PSPP_SHEET_SELECTION_MULTIPLE &&
- selection->type != PSPP_SHEET_SELECTION_RECTANGLE,
- FALSE);
- g_return_val_if_fail (selection->tree_view != NULL, FALSE);
-
- /* Clear the iter */
- if (iter)
- memset (iter, 0, sizeof (GtkTreeIter));
-
- if (model)
- *model = selection->tree_view->priv->model;
-
- if (selection->tree_view->priv->anchor == NULL)
- return FALSE;
-
- anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
-
- if (anchor_path == NULL)
- return FALSE;
-
- retval = FALSE;
-
- _pspp_sheet_view_find_node (selection->tree_view,
- anchor_path,
- &node);
-
- if (pspp_sheet_view_node_is_selected (selection->tree_view, node))
- {
- /* we only want to return the anchor if it exists in the rbtree and
- * is selected.
- */
- if (iter == NULL)
- retval = TRUE;
- else
- retval = gtk_tree_model_get_iter (selection->tree_view->priv->model,
- iter,
- anchor_path);
- }
- else
- {
- /* We don't want to return the anchor if it isn't actually selected.
- */
- retval = FALSE;
- }
-
- gtk_tree_path_free (anchor_path);
-
- return retval;
-}
-
-/**
- * pspp_sheet_selection_get_selected_rows:
- * @selection: A #PsppSheetSelection.
- * @model: (allow-none): A pointer to set to the #GtkTreeModel, or NULL.
- *
- * Creates a list of path of all selected rows. Additionally, if you are
- * planning on modifying the model after calling this function, you may
- * want to convert the returned list into a list of #GtkTreeRowReference<!-- -->s.
- * To do this, you can use gtk_tree_row_reference_new().
- *
- * To free the return value, use:
- * |[
- * g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
- * g_list_free (list);
- * ]|
- *
- * Return value: (element-type GtkTreePath) (transfer full): A #GList containing a #GtkTreePath for each selected row.
- *
- * Since: 2.2
- **/
-GList *
-pspp_sheet_selection_get_selected_rows (PsppSheetSelection *selection,
- GtkTreeModel **model)
-{
- const struct range_tower_node *node;
- unsigned long int start;
- GList *list = NULL;
-
- g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), NULL);
- g_return_val_if_fail (selection->tree_view != NULL, NULL);
-
- if (model)
- *model = selection->tree_view->priv->model;
-
- if (selection->tree_view->priv->row_count == 0)
- return NULL;
-
- if (selection->type == PSPP_SHEET_SELECTION_NONE)
- return NULL;
- else if (selection->type != PSPP_SHEET_SELECTION_MULTIPLE &&
- selection->type != PSPP_SHEET_SELECTION_RECTANGLE)
- {
- GtkTreeIter iter;
-
- if (pspp_sheet_selection_get_selected (selection, NULL, &iter))
- {
- GtkTreePath *path;
-
- path = gtk_tree_model_get_path (selection->tree_view->priv->model, &iter);
- list = g_list_append (list, path);
-
- return list;
- }
-
- return NULL;
- }
-
- RANGE_TOWER_FOR_EACH (node, start, selection->tree_view->priv->selected)
- {
- unsigned long int width = range_tower_node_get_width (node);
- unsigned long int index;
-
- for (index = start; index < start + width; index++)
- list = g_list_prepend (list, gtk_tree_path_new_from_indices (index, -1));
- }
-
- return g_list_reverse (list);
-}
-
-/**
- * pspp_sheet_selection_count_selected_rows:
- * @selection: A #PsppSheetSelection.
- *
- * Returns the number of rows that have been selected in @tree.
- *
- * Return value: The number of rows selected.
- *
- * Since: 2.2
- **/
-gint
-pspp_sheet_selection_count_selected_rows (PsppSheetSelection *selection)
-{
- const struct range_tower_node *node;
- unsigned long int start;
- gint count = 0;
-
- g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), 0);
- g_return_val_if_fail (selection->tree_view != NULL, 0);
-
- if (selection->tree_view->priv->row_count == 0)
- return 0;
-
- if (selection->type == PSPP_SHEET_SELECTION_SINGLE ||
- selection->type == PSPP_SHEET_SELECTION_BROWSE)
- {
- if (pspp_sheet_selection_get_selected (selection, NULL, NULL))
- return 1;
- else
- return 0;
- }
-
- count = 0;
- RANGE_TOWER_FOR_EACH (node, start, selection->tree_view->priv->selected)
- count += range_tower_node_get_width (node);
-
- return count;
-}
-
-/* pspp_sheet_selection_selected_foreach helper */
-static void
-model_changed (gpointer data)
-{
- gboolean *stop = (gboolean *)data;
-
- *stop = TRUE;
-}
-
-/**
- * pspp_sheet_selection_selected_foreach:
- * @selection: A #PsppSheetSelection.
- * @func: The function to call for each selected node.
- * @data: user data to pass to the function.
- *
- * Calls a function for each selected node. Note that you cannot modify
- * the tree or selection from within this function. As a result,
- * pspp_sheet_selection_get_selected_rows() might be more useful.
- **/
-void
-pspp_sheet_selection_selected_foreach (PsppSheetSelection *selection,
- PsppSheetSelectionForeachFunc func,
- gpointer data)
-{
- const struct range_tower_node *node;
- unsigned long int start;
- GtkTreePath *path;
- GtkTreeIter iter;
- GtkTreeModel *model;
-
- gulong inserted_id, deleted_id, reordered_id, changed_id;
- gboolean stop = FALSE;
-
- g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
- g_return_if_fail (selection->tree_view != NULL);
-
- if (func == NULL ||
- selection->tree_view->priv->row_count == 0)
- return;
-
- if (selection->type == PSPP_SHEET_SELECTION_SINGLE ||
- selection->type == PSPP_SHEET_SELECTION_BROWSE)
- {
- if (gtk_tree_row_reference_valid (selection->tree_view->priv->anchor))
- {
- path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
- gtk_tree_model_get_iter (selection->tree_view->priv->model, &iter, path);
- (* func) (selection->tree_view->priv->model, path, &iter, data);
- gtk_tree_path_free (path);
- }
- return;
- }
-
- model = selection->tree_view->priv->model;
- g_object_ref (model);
-
- /* connect to signals to monitor changes in treemodel */
- inserted_id = g_signal_connect_swapped (model, "row-inserted",
- G_CALLBACK (model_changed),
- &stop);
- deleted_id = g_signal_connect_swapped (model, "row-deleted",
- G_CALLBACK (model_changed),
- &stop);
- reordered_id = g_signal_connect_swapped (model, "rows-reordered",
- G_CALLBACK (model_changed),
- &stop);
- changed_id = g_signal_connect_swapped (selection->tree_view, "notify::model",
- G_CALLBACK (model_changed),
- &stop);
-
- RANGE_TOWER_FOR_EACH (node, start, selection->tree_view->priv->selected)
- {
- unsigned long int width = range_tower_node_get_width (node);
- unsigned long int index;
-
- for (index = start; index < start + width; index++)
- {
- GtkTreePath *path;
- GtkTreeIter iter;
-
- path = gtk_tree_path_new_from_indices (index, -1);
- gtk_tree_model_get_iter (model, &iter, path);
- (* func) (model, path, &iter, data);
- gtk_tree_path_free (path);
- }
- }
-
- g_signal_handler_disconnect (model, inserted_id);
- g_signal_handler_disconnect (model, deleted_id);
- g_signal_handler_disconnect (model, reordered_id);
- g_signal_handler_disconnect (selection->tree_view, changed_id);
- g_object_unref (model);
-
- /* check if we have to spew a scary message */
- if (stop)
- g_warning ("The model has been modified from within pspp_sheet_selection_selected_foreach.\n"
- "This function is for observing the selections of the tree only. If\n"
- "you are trying to get all selected items from the tree, try using\n"
- "pspp_sheet_selection_get_selected_rows instead.\n");
-}
-
-/**
- * pspp_sheet_selection_select_path:
- * @selection: A #PsppSheetSelection.
- * @path: The #GtkTreePath to be selected.
- *
- * Select the row at @path.
- **/
-void
-pspp_sheet_selection_select_path (PsppSheetSelection *selection,
- GtkTreePath *path)
-{
- int node;
- PsppSheetSelectMode mode = 0;
-
- g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
- g_return_if_fail (selection->tree_view != NULL);
- g_return_if_fail (path != NULL);
-
- _pspp_sheet_view_find_node (selection->tree_view,
- path,
- &node);
-
- if (node < 0 || pspp_sheet_view_node_is_selected (selection->tree_view, node))
- return;
-
- if (selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
- selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
- mode = PSPP_SHEET_SELECT_MODE_TOGGLE;
-
- _pspp_sheet_selection_internal_select_node (selection,
- node,
- path,
- mode,
- FALSE);
-}
-
-/**
- * pspp_sheet_selection_unselect_path:
- * @selection: A #PsppSheetSelection.
- * @path: The #GtkTreePath to be unselected.
- *
- * Unselects the row at @path.
- **/
-void
-pspp_sheet_selection_unselect_path (PsppSheetSelection *selection,
- GtkTreePath *path)
-{
- int node;
-
- g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
- g_return_if_fail (selection->tree_view != NULL);
- g_return_if_fail (path != NULL);
-
- _pspp_sheet_view_find_node (selection->tree_view,
- path,
- &node);
-
- if (node < 0 || !pspp_sheet_view_node_is_selected (selection->tree_view, node))
- return;
-
- _pspp_sheet_selection_internal_select_node (selection,
- node,
- path,
- PSPP_SHEET_SELECT_MODE_TOGGLE,
- TRUE);
-}
-
-/**
- * pspp_sheet_selection_select_iter:
- * @selection: A #PsppSheetSelection.
- * @iter: The #GtkTreeIter to be selected.
- *
- * Selects the specified iterator.
- **/
-void
-pspp_sheet_selection_select_iter (PsppSheetSelection *selection,
- GtkTreeIter *iter)
-{
- GtkTreePath *path;
-
- g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
- g_return_if_fail (selection->tree_view != NULL);
- g_return_if_fail (selection->tree_view->priv->model != NULL);
- g_return_if_fail (iter != NULL);
-
- path = gtk_tree_model_get_path (selection->tree_view->priv->model,
- iter);
-
- if (path == NULL)
- return;
-
- pspp_sheet_selection_select_path (selection, path);
- gtk_tree_path_free (path);
-}
-
-
-/**
- * pspp_sheet_selection_unselect_iter:
- * @selection: A #PsppSheetSelection.
- * @iter: The #GtkTreeIter to be unselected.
- *
- * Unselects the specified iterator.
- **/
-void
-pspp_sheet_selection_unselect_iter (PsppSheetSelection *selection,
- GtkTreeIter *iter)
-{
- GtkTreePath *path;
-
- g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
- g_return_if_fail (selection->tree_view != NULL);
- g_return_if_fail (selection->tree_view->priv->model != NULL);
- g_return_if_fail (iter != NULL);
-
- path = gtk_tree_model_get_path (selection->tree_view->priv->model,
- iter);
-
- if (path == NULL)
- return;
-
- pspp_sheet_selection_unselect_path (selection, path);
- gtk_tree_path_free (path);
-}
-
-/**
- * pspp_sheet_selection_path_is_selected:
- * @selection: A #PsppSheetSelection.
- * @path: A #GtkTreePath to check selection on.
- *
- * Returns %TRUE if the row pointed to by @path is currently selected. If @path
- * does not point to a valid location, %FALSE is returned
- *
- * Return value: %TRUE if @path is selected.
- **/
-gboolean
-pspp_sheet_selection_path_is_selected (PsppSheetSelection *selection,
- GtkTreePath *path)
-{
- int node;
-
- g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), FALSE);
- g_return_val_if_fail (path != NULL, FALSE);
- g_return_val_if_fail (selection->tree_view != NULL, FALSE);
-
- if (selection->tree_view->priv->model == NULL)
- return FALSE;
-
- _pspp_sheet_view_find_node (selection->tree_view,
- path,
- &node);
-
- if (node < 0 || !pspp_sheet_view_node_is_selected (selection->tree_view, node))
- return FALSE;
-
- return TRUE;
-}
-
-/**
- * pspp_sheet_selection_iter_is_selected:
- * @selection: A #PsppSheetSelection
- * @iter: A valid #GtkTreeIter
- *
- * Returns %TRUE if the row at @iter is currently selected.
- *
- * Return value: %TRUE, if @iter is selected
- **/
-gboolean
-pspp_sheet_selection_iter_is_selected (PsppSheetSelection *selection,
- GtkTreeIter *iter)
-{
- GtkTreePath *path;
- gboolean retval;
-
- g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), FALSE);
- g_return_val_if_fail (iter != NULL, FALSE);
- g_return_val_if_fail (selection->tree_view != NULL, FALSE);
- g_return_val_if_fail (selection->tree_view->priv->model != NULL, FALSE);
-
- path = gtk_tree_model_get_path (selection->tree_view->priv->model, iter);
- if (path == NULL)
- return FALSE;
-
- retval = pspp_sheet_selection_path_is_selected (selection, path);
- gtk_tree_path_free (path);
-
- return retval;
-}
-
-
-/* We have a real_{un,}select_all function that doesn't emit the signal, so we
- * can use it in other places without fear of the signal being emitted.
- */
-static gint
-pspp_sheet_selection_real_select_all (PsppSheetSelection *selection)
-{
- const struct range_tower_node *node;
- int row_count = selection->tree_view->priv->row_count;
-
- if (row_count == 0)
- return FALSE;
-
- node = range_tower_first (selection->tree_view->priv->selected);
- if (node
- && range_tower_node_get_start (node) == 0
- && range_tower_node_get_width (node) >= row_count)
- return FALSE;
-
- range_tower_set1 (selection->tree_view->priv->selected, 0, row_count);
- pspp_sheet_selection_select_all_columns (selection);
-
- /* XXX we could invalidate individual visible rows instead */
- gdk_window_invalidate_rect (selection->tree_view->priv->bin_window, NULL, TRUE);
-
- return TRUE;
-}
-
-/**
- * pspp_sheet_selection_select_all:
- * @selection: A #PsppSheetSelection.
- *
- * Selects all the nodes and column. @selection must be set to
- * #PSPP_SHEET_SELECTION_MULTIPLE or #PSPP_SHEET_SELECTION_RECTANGLE mode.
- **/
-void
-pspp_sheet_selection_select_all (PsppSheetSelection *selection)
-{
- g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
- g_return_if_fail (selection->tree_view != NULL);
-
- if (selection->tree_view->priv->row_count == 0 || selection->tree_view->priv->model == NULL)
- return;
-
- g_return_if_fail (selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
- selection->type == PSPP_SHEET_SELECTION_RECTANGLE);
-
- if (pspp_sheet_selection_real_select_all (selection))
- g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
-}
-
-static gint
-pspp_sheet_selection_real_unselect_all (PsppSheetSelection *selection)
-{
- if (selection->type == PSPP_SHEET_SELECTION_SINGLE ||
- selection->type == PSPP_SHEET_SELECTION_BROWSE)
- {
- int node = -1;
- GtkTreePath *anchor_path;
-
- if (selection->tree_view->priv->anchor == NULL)
- return FALSE;
-
- anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
-
- if (anchor_path == NULL)
- return FALSE;
-
- _pspp_sheet_view_find_node (selection->tree_view,
- anchor_path,
- &node);
-
- gtk_tree_path_free (anchor_path);
-
- if (node < 0)
- return FALSE;
-
- if (pspp_sheet_view_node_is_selected (selection->tree_view, node))
- {
- if (pspp_sheet_selection_real_select_node (selection, node, FALSE))
- {
- gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
- selection->tree_view->priv->anchor = NULL;
- return TRUE;
- }
- }
- return FALSE;
- }
- else if (range_tower_is_empty (selection->tree_view->priv->selected))
- return FALSE;
- else
- {
- range_tower_set0 (selection->tree_view->priv->selected, 0, ULONG_MAX);
- pspp_sheet_selection_unselect_all_columns (selection);
-
- /* XXX we could invalidate individual visible rows instead */
- gdk_window_invalidate_rect (selection->tree_view->priv->bin_window, NULL, TRUE);
-
- return TRUE;
- }
-}
-
-/**
- * pspp_sheet_selection_unselect_all:
- * @selection: A #PsppSheetSelection.
- *
- * Unselects all the nodes and columns.
- **/
-void
-pspp_sheet_selection_unselect_all (PsppSheetSelection *selection)
-{
- g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
- g_return_if_fail (selection->tree_view != NULL);
-
- if (selection->tree_view->priv->row_count == 0 || selection->tree_view->priv->model == NULL)
- return;
-
- if (pspp_sheet_selection_real_unselect_all (selection))
- g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
-}
-
-enum
-{
- RANGE_SELECT,
- RANGE_UNSELECT
-};
-
-static gint
-pspp_sheet_selection_real_modify_range (PsppSheetSelection *selection,
- gint mode,
- GtkTreePath *start_path,
- GtkTreePath *end_path)
-{
- int start_node, end_node;
- GtkTreePath *anchor_path = NULL;
- gboolean dirty = FALSE;
-
- switch (gtk_tree_path_compare (start_path, end_path))
- {
- case 1:
- _pspp_sheet_view_find_node (selection->tree_view,
- end_path,
- &start_node);
- _pspp_sheet_view_find_node (selection->tree_view,
- start_path,
- &end_node);
- anchor_path = start_path;
- break;
- case 0:
- _pspp_sheet_view_find_node (selection->tree_view,
- start_path,
- &start_node);
- end_node = start_node;
- anchor_path = start_path;
- break;
- case -1:
- _pspp_sheet_view_find_node (selection->tree_view,
- start_path,
- &start_node);
- _pspp_sheet_view_find_node (selection->tree_view,
- end_path,
- &end_node);
- anchor_path = start_path;
- break;
- }
-
- g_return_val_if_fail (start_node >= 0, FALSE);
- g_return_val_if_fail (end_node >= 0, FALSE);
-
- if (anchor_path)
- {
- if (selection->tree_view->priv->anchor)
- gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
-
- selection->tree_view->priv->anchor =
- gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view),
- selection->tree_view->priv->model,
- anchor_path);
- }
-
- do
- {
- dirty |= pspp_sheet_selection_real_select_node (selection, start_node, (mode == RANGE_SELECT)?TRUE:FALSE);
-
- if (start_node == end_node)
- break;
-
- start_node = pspp_sheet_view_node_next (selection->tree_view, start_node);
- if (start_node < 0)
- {
- /* we just ran out of tree. That means someone passed in bogus values.
- */
- return dirty;
- }
- }
- while (TRUE);
-
- return dirty;
-}
-
-/**
- * pspp_sheet_selection_select_range:
- * @selection: A #PsppSheetSelection.
- * @start_path: The initial node of the range.
- * @end_path: The final node of the range.
- *
- * Selects a range of nodes, determined by @start_path and @end_path inclusive.
- * @selection must be set to #PSPP_SHEET_SELECTION_MULTIPLE or
- * #PSPP_SHEET_SELECTION_RECTANGLE mode.
- **/
-void
-pspp_sheet_selection_select_range (PsppSheetSelection *selection,
- GtkTreePath *start_path,
- GtkTreePath *end_path)
-{
- g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
- g_return_if_fail (selection->tree_view != NULL);
- g_return_if_fail (selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
- selection->type == PSPP_SHEET_SELECTION_RECTANGLE);
- g_return_if_fail (selection->tree_view->priv->model != NULL);
-
- if (pspp_sheet_selection_real_modify_range (selection, RANGE_SELECT, start_path, end_path))
- g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
-}
-
-/**
- * pspp_sheet_selection_unselect_range:
- * @selection: A #PsppSheetSelection.
- * @start_path: The initial node of the range.
- * @end_path: The initial node of the range.
- *
- * Unselects a range of nodes, determined by @start_path and @end_path
- * inclusive.
- *
- * Since: 2.2
- **/
-void
-pspp_sheet_selection_unselect_range (PsppSheetSelection *selection,
- GtkTreePath *start_path,
- GtkTreePath *end_path)
-{
- g_return_if_fail (PSPP_IS_SHEET_SELECTION (selection));
- g_return_if_fail (selection->tree_view != NULL);
- g_return_if_fail (selection->tree_view->priv->model != NULL);
-
- if (pspp_sheet_selection_real_modify_range (selection, RANGE_UNSELECT, start_path, end_path))
- g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
-}
-
-struct range_set *
-pspp_sheet_selection_get_range_set (PsppSheetSelection *selection)
-{
- const struct range_tower_node *node;
- unsigned long int start;
- struct range_set *set;
-
- g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection),
- range_set_create ());
- g_return_val_if_fail (selection->tree_view != NULL, range_set_create ());
-
- set = range_set_create ();
- RANGE_TOWER_FOR_EACH (node, start, selection->tree_view->priv->selected)
- range_set_set1 (set, start, range_tower_node_get_width (node));
- return set;
-}
-
-/* Called internally by gtktreeview.c It handles actually selecting the tree.
- */
-
-/*
- * docs about the 'override_browse_mode', we set this flag when we want to
- * unset select the node and override the select browse mode behaviour (that is
- * 'one node should *always* be selected').
- */
-void
-_pspp_sheet_selection_internal_select_node (PsppSheetSelection *selection,
- int node,
- GtkTreePath *path,
- PsppSheetSelectMode mode,
- gboolean override_browse_mode)
-{
- gint dirty = FALSE;
- GtkTreePath *anchor_path = NULL;
-
- if (selection->type == PSPP_SHEET_SELECTION_NONE)
- return;
-
- if (selection->tree_view->priv->anchor)
- anchor_path = gtk_tree_row_reference_get_path (selection->tree_view->priv->anchor);
-
- if (selection->type == PSPP_SHEET_SELECTION_SINGLE ||
- selection->type == PSPP_SHEET_SELECTION_BROWSE)
- {
- /* just unselect */
- if (selection->type == PSPP_SHEET_SELECTION_BROWSE && override_browse_mode)
- {
- dirty = pspp_sheet_selection_real_unselect_all (selection);
- }
- /* Did we try to select the same node again? */
- else if (selection->type == PSPP_SHEET_SELECTION_SINGLE &&
- anchor_path && gtk_tree_path_compare (path, anchor_path) == 0)
- {
- if ((mode & PSPP_SHEET_SELECT_MODE_TOGGLE) == PSPP_SHEET_SELECT_MODE_TOGGLE)
- {
- dirty = pspp_sheet_selection_real_unselect_all (selection);
- }
- }
- else
- {
- if (anchor_path)
- {
- dirty = pspp_sheet_selection_real_unselect_all (selection);
-
- /* if dirty is TRUE at this point, we successfully unselected the
- * old one, and can then select the new one */
- if (dirty)
- {
- if (selection->tree_view->priv->anchor)
- {
- gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
- selection->tree_view->priv->anchor = NULL;
- }
-
- if (pspp_sheet_selection_real_select_node (selection, node, TRUE))
- {
- selection->tree_view->priv->anchor =
- gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
- }
- }
- }
- else
- {
- if (pspp_sheet_selection_real_select_node (selection, node, TRUE))
- {
- dirty = TRUE;
- if (selection->tree_view->priv->anchor)
- gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
-
- selection->tree_view->priv->anchor =
- gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
- }
- }
- }
- }
- else if (selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
- selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
- {
- if ((mode & PSPP_SHEET_SELECT_MODE_EXTEND) == PSPP_SHEET_SELECT_MODE_EXTEND
- && (anchor_path == NULL))
- {
- if (selection->tree_view->priv->anchor)
- gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
-
- selection->tree_view->priv->anchor =
- gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
- dirty = pspp_sheet_selection_real_select_node (selection, node, TRUE);
- }
- else if ((mode & (PSPP_SHEET_SELECT_MODE_EXTEND | PSPP_SHEET_SELECT_MODE_TOGGLE)) == (PSPP_SHEET_SELECT_MODE_EXTEND | PSPP_SHEET_SELECT_MODE_TOGGLE))
- {
- pspp_sheet_selection_select_range (selection,
- anchor_path,
- path);
- }
- else if ((mode & PSPP_SHEET_SELECT_MODE_TOGGLE) == PSPP_SHEET_SELECT_MODE_TOGGLE)
- {
- bool selected = pspp_sheet_view_node_is_selected (selection->tree_view, node);
- if (selection->tree_view->priv->anchor)
- gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
-
- selection->tree_view->priv->anchor =
- gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
-
- if (selected)
- dirty |= pspp_sheet_selection_real_select_node (selection, node, FALSE);
- else
- dirty |= pspp_sheet_selection_real_select_node (selection, node, TRUE);
- }
- else if ((mode & PSPP_SHEET_SELECT_MODE_EXTEND) == PSPP_SHEET_SELECT_MODE_EXTEND)
- {
- dirty = pspp_sheet_selection_real_unselect_all (selection);
- dirty |= pspp_sheet_selection_real_modify_range (selection,
- RANGE_SELECT,
- anchor_path,
- path);
- }
- else
- {
- dirty = pspp_sheet_selection_real_unselect_all (selection);
-
- if (selection->tree_view->priv->anchor)
- gtk_tree_row_reference_free (selection->tree_view->priv->anchor);
-
- selection->tree_view->priv->anchor =
- gtk_tree_row_reference_new_proxy (G_OBJECT (selection->tree_view), selection->tree_view->priv->model, path);
-
- dirty |= pspp_sheet_selection_real_select_node (selection, node, TRUE);
- }
- }
-
- if (anchor_path)
- gtk_tree_path_free (anchor_path);
-
- if (dirty)
- g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
-}
-
-
-void
-_pspp_sheet_selection_emit_changed (PsppSheetSelection *selection)
-{
- g_signal_emit (selection, tree_selection_signals[CHANGED], 0);
-}
-
-/* NOTE: Any {un,}selection ever done _MUST_ be done through this function!
- */
-
-static gint
-pspp_sheet_selection_real_select_node (PsppSheetSelection *selection,
- int node,
- gboolean select)
-{
- select = !! select;
- if (pspp_sheet_view_node_is_selected (selection->tree_view, node) != select)
- {
- if (select)
- pspp_sheet_view_node_select (selection->tree_view, node);
- else
- pspp_sheet_view_node_unselect (selection->tree_view, node);
-
- _pspp_sheet_view_queue_draw_node (selection->tree_view, node, NULL);
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-void
-pspp_sheet_selection_unselect_all_columns (PsppSheetSelection *selection)
-{
- PsppSheetView *sheet_view = selection->tree_view;
- gboolean changed;
- GList *list;
-
- changed = FALSE;
- for (list = sheet_view->priv->columns; list; list = list->next)
- {
- PsppSheetViewColumn *column = list->data;
- if (column->selected)
- {
- column->selected = FALSE;
- changed = TRUE;
- }
- }
- if (changed && selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
- {
- gtk_widget_queue_draw (GTK_WIDGET (selection->tree_view));
- _pspp_sheet_selection_emit_changed (selection);
- }
-}
-
-GList *
-pspp_sheet_selection_get_selected_columns (PsppSheetSelection *selection)
-{
- PsppSheetView *sheet_view = selection->tree_view;
- GList *selected_columns = NULL;
- GList *iter;
-
- g_return_val_if_fail (PSPP_IS_SHEET_SELECTION (selection), NULL);
- g_return_val_if_fail (selection->tree_view != NULL, NULL);
-
- if (selection->type != PSPP_SHEET_SELECTION_RECTANGLE)
- return NULL;
-
- for (iter = sheet_view->priv->columns; iter; iter = iter->next)
- {
- PsppSheetViewColumn *column = iter->data;
- if (column->selected)
- selected_columns = g_list_prepend (selected_columns, column);
- }
- return g_list_reverse (selected_columns);
-}
-
-gint
-pspp_sheet_selection_count_selected_columns (PsppSheetSelection *selection)
-{
- PsppSheetView *sheet_view = selection->tree_view;
- GList *list;
- gint n;
-
- n = 0;
- for (list = sheet_view->priv->columns; list; list = list->next)
- {
- PsppSheetViewColumn *column = list->data;
- if (column->selected)
- n++;
- }
- return n;
-}
-
-void
-pspp_sheet_selection_select_all_columns (PsppSheetSelection *selection)
-{
- PsppSheetView *sheet_view = selection->tree_view;
- gboolean changed;
- GList *list;
-
- changed = FALSE;
- for (list = sheet_view->priv->columns; list; list = list->next)
- {
- PsppSheetViewColumn *column = list->data;
- if (!column->selected && column->selectable)
- {
- /* XXX should use pspp_sheet_view_column_set_selected() here (and
- elsewhere) but we want to call
- _pspp_sheet_selection_emit_changed() only once for all the
- columns. */
- column->selected = TRUE;
- changed = TRUE;
- }
- }
- if (changed && selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
- {
- _pspp_sheet_selection_emit_changed (selection);
- gtk_widget_queue_draw (GTK_WIDGET (selection->tree_view));
- }
-}
-
-void
-pspp_sheet_selection_select_column (PsppSheetSelection *selection,
- PsppSheetViewColumn *column)
-{
- if (!column->selected && column->selectable)
- {
- column->selected = TRUE;
- if (selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
- {
- _pspp_sheet_selection_emit_changed (selection);
- gtk_widget_queue_draw (GTK_WIDGET (selection->tree_view));
- }
- }
-}
-
-void
-pspp_sheet_selection_select_column_range (PsppSheetSelection *selection,
- PsppSheetViewColumn *first,
- PsppSheetViewColumn *last)
-{
- PsppSheetView *sheet_view = selection->tree_view;
- gboolean in_range;
- gboolean changed;
- GList *list;
-
- in_range = FALSE;
- changed = FALSE;
- for (list = sheet_view->priv->columns; list; list = list->next)
- {
- PsppSheetViewColumn *column = list->data;
- gboolean c0 = column == first;
- gboolean c1 = column == last;
-
- if (in_range || c0 || c1)
- {
- if (!column->selected && column->selectable)
- {
- column->selected = TRUE;
- changed = TRUE;
- }
- }
-
- in_range = in_range ^ c0 ^ c1;
- }
- if (changed && selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
- {
- _pspp_sheet_selection_emit_changed (selection);
- gtk_widget_queue_draw (GTK_WIDGET (selection->tree_view));
- }
-}
+++ /dev/null
-/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2011 Free Software Foundation, Inc.
-
- 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/>. */
-
-/* gtktreeselection.h
- * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * 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.
- */
-
-#ifndef __PSPP_SHEET_SELECTION_H__
-#define __PSPP_SHEET_SELECTION_H__
-
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-
-#define PSPP_TYPE_SHEET_SELECTION (pspp_sheet_selection_get_type ())
-#define PSPP_SHEET_SELECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PSPP_TYPE_SHEET_SELECTION, PsppSheetSelection))
-#define PSPP_SHEET_SELECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PSPP_TYPE_SHEET_SELECTION, PsppSheetSelectionClass))
-#define PSPP_IS_SHEET_SELECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPP_TYPE_SHEET_SELECTION))
-#define PSPP_IS_SHEET_SELECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPP_TYPE_SHEET_SELECTION))
-#define PSPP_SHEET_SELECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PSPP_TYPE_SHEET_SELECTION, PsppSheetSelectionClass))
-
-typedef enum
- {
- /* Same as GtkSelectionMode. */
- PSPP_SHEET_SELECTION_NONE = GTK_SELECTION_NONE,
- PSPP_SHEET_SELECTION_SINGLE = GTK_SELECTION_SINGLE,
- PSPP_SHEET_SELECTION_BROWSE = GTK_SELECTION_BROWSE,
- PSPP_SHEET_SELECTION_MULTIPLE = GTK_SELECTION_MULTIPLE,
-
- /* PsppSheetView extension. */
- PSPP_SHEET_SELECTION_RECTANGLE = 10
- }
-PsppSheetSelectionMode;
-
-typedef gboolean (* PsppSheetSelectionFunc) (PsppSheetSelection *selection,
- GtkTreeModel *model,
- GtkTreePath *path,
- gboolean path_currently_selected,
- gpointer data);
-typedef void (* PsppSheetSelectionForeachFunc) (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer data);
-
-struct _PsppSheetSelection
-{
- GObject parent;
-
- /*< private >*/
-
- PsppSheetView *PSEAL (tree_view);
- PsppSheetSelectionMode PSEAL (type);
-};
-
-struct _PsppSheetSelectionClass
-{
- GObjectClass parent_class;
-
- void (* changed) (PsppSheetSelection *selection);
-
- /* Padding for future expansion */
- void (*_gtk_reserved1) (void);
- void (*_gtk_reserved2) (void);
- void (*_gtk_reserved3) (void);
- void (*_gtk_reserved4) (void);
-};
-
-
-GType pspp_sheet_selection_get_type (void) G_GNUC_CONST;
-
-void pspp_sheet_selection_set_mode (PsppSheetSelection *selection,
- PsppSheetSelectionMode type);
-PsppSheetSelectionMode pspp_sheet_selection_get_mode (PsppSheetSelection *selection);
-void pspp_sheet_selection_set_select_function (PsppSheetSelection *selection,
- PsppSheetSelectionFunc func,
- gpointer data,
- GDestroyNotify destroy);
-gpointer pspp_sheet_selection_get_user_data (PsppSheetSelection *selection);
-PsppSheetView* pspp_sheet_selection_get_tree_view (PsppSheetSelection *selection);
-
-PsppSheetSelectionFunc pspp_sheet_selection_get_select_function (PsppSheetSelection *selection);
-
-/* Only meaningful if PSPP_SHEET_SELECTION_SINGLE or PSPP_SHEET_SELECTION_BROWSE is set */
-/* Use selected_foreach or get_selected_rows for
- PSPP_SHEET_SELECTION_MULTIPLE */
-gboolean pspp_sheet_selection_get_selected (PsppSheetSelection *selection,
- GtkTreeModel **model,
- GtkTreeIter *iter);
-GList * pspp_sheet_selection_get_selected_rows (PsppSheetSelection *selection,
- GtkTreeModel **model);
-gint pspp_sheet_selection_count_selected_rows (PsppSheetSelection *selection);
-void pspp_sheet_selection_selected_foreach (PsppSheetSelection *selection,
- PsppSheetSelectionForeachFunc func,
- gpointer data);
-void pspp_sheet_selection_select_path (PsppSheetSelection *selection,
- GtkTreePath *path);
-void pspp_sheet_selection_unselect_path (PsppSheetSelection *selection,
- GtkTreePath *path);
-void pspp_sheet_selection_select_iter (PsppSheetSelection *selection,
- GtkTreeIter *iter);
-void pspp_sheet_selection_unselect_iter (PsppSheetSelection *selection,
- GtkTreeIter *iter);
-gboolean pspp_sheet_selection_path_is_selected (PsppSheetSelection *selection,
- GtkTreePath *path);
-gboolean pspp_sheet_selection_iter_is_selected (PsppSheetSelection *selection,
- GtkTreeIter *iter);
-void pspp_sheet_selection_select_all (PsppSheetSelection *selection);
-void pspp_sheet_selection_unselect_all (PsppSheetSelection *selection);
-void pspp_sheet_selection_select_range (PsppSheetSelection *selection,
- GtkTreePath *start_path,
- GtkTreePath *end_path);
-void pspp_sheet_selection_unselect_range (PsppSheetSelection *selection,
- GtkTreePath *start_path,
- GtkTreePath *end_path);
-struct range_set *pspp_sheet_selection_get_range_set (PsppSheetSelection *selection);
-
-
-GList * pspp_sheet_selection_get_selected_columns (PsppSheetSelection *selection);
-gint pspp_sheet_selection_count_selected_columns (PsppSheetSelection *selection);
-void pspp_sheet_selection_select_all_columns (PsppSheetSelection *selection);
-void pspp_sheet_selection_unselect_all_columns (PsppSheetSelection *selection);
-void pspp_sheet_selection_select_column (PsppSheetSelection *selection,
- PsppSheetViewColumn *column);
-void pspp_sheet_selection_select_column_range (PsppSheetSelection *selection,
- PsppSheetViewColumn *first,
- PsppSheetViewColumn *last);
-
-G_END_DECLS
-
-#endif /* __PSPP_SHEET_SELECTION_H__ */
+++ /dev/null
-/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2011, 2012, 2015 Free Software Foundation, Inc.
-
- 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/>. */
-
-/* gtktreeviewcolumn.c
- * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * 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 "ui/gui/pspp-sheet-private.h"
-
-#include <errno.h>
-#include <gtk/gtk.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "ui/gui/psppire-marshal.h"
-#include "ui/gui/pspp-sheet-selection.h"
-#include "ui/gui/pspp-widget-facade.h"
-
-#define P_(STRING) STRING
-#define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
-#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
-
-enum
-{
- PROP_0,
- PROP_VISIBLE,
- PROP_RESIZABLE,
- PROP_WIDTH,
- PROP_SPACING,
- PROP_FIXED_WIDTH,
- PROP_MIN_WIDTH,
- PROP_MAX_WIDTH,
- PROP_TITLE,
- PROP_EXPAND,
- PROP_CLICKABLE,
- PROP_WIDGET,
- PROP_ALIGNMENT,
- PROP_REORDERABLE,
- PROP_SORT_INDICATOR,
- PROP_SORT_ORDER,
- PROP_SORT_COLUMN_ID,
- PROP_QUICK_EDIT,
- PROP_SELECTED,
- PROP_SELECTABLE,
- PROP_ROW_HEAD,
- PROP_TABBABLE
-};
-
-enum
-{
- CLICKED,
- QUERY_TOOLTIP,
- POPUP_MENU,
- BUTTON_PRESS_EVENT,
- LAST_SIGNAL
-};
-
-typedef struct _PsppSheetViewColumnCellInfo PsppSheetViewColumnCellInfo;
-struct _PsppSheetViewColumnCellInfo
-{
- GtkCellRenderer *cell;
- GSList *attributes;
- PsppSheetCellDataFunc func;
- gpointer func_data;
- GDestroyNotify destroy;
- gint requested_width;
- gint real_width;
- guint expand : 1;
- guint pack : 1;
- guint has_focus : 1;
- guint in_editing_mode : 1;
-};
-
-/* Type methods */
-static void pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface);
-
-/* GObject methods */
-static void pspp_sheet_view_column_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-static void pspp_sheet_view_column_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
-static void pspp_sheet_view_column_finalize (GObject *object);
-
-/* GtkCellLayout implementation */
-static void pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
- GtkCellRenderer *cell,
- gboolean expand);
-static void pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
- GtkCellRenderer *cell,
- gboolean expand);
-static void pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout);
-static void pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
- GtkCellRenderer *cell,
- const gchar *attribute,
- gint column);
-static void pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
- GtkCellRenderer *cell,
- GtkCellLayoutDataFunc func,
- gpointer func_data,
- GDestroyNotify destroy);
-static void pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
- GtkCellRenderer *cell);
-static void pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
- GtkCellRenderer *cell,
- gint position);
-static GList *pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *cell_layout);
-
-/* Button handling code */
-static void pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column);
-void pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column);
-
-/* Button signal handlers */
-static gint pspp_sheet_view_column_button_event (GtkWidget *widget,
- GdkEventButton *event,
- gpointer data);
-static void pspp_sheet_view_column_button_clicked (GtkWidget *widget,
- gpointer data);
-static void pspp_sheet_view_column_button_popup_menu (GtkWidget *widget,
- gpointer data);
-static gboolean pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
- gboolean group_cycling,
- gpointer data);
-static gboolean on_pspp_sheet_view_column_button_clicked (PsppSheetViewColumn *);
-static gboolean on_pspp_sheet_view_column_button_press_event (PsppSheetViewColumn *,
- GdkEventButton *);
-
-/* Property handlers */
-static void pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
- PsppSheetViewColumn *tree_column);
-
-/* Internal functions */
-static void pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
- gpointer data);
-static void pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column);
-static void pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell_renderer,
- va_list args);
-static PsppSheetViewColumnCellInfo *pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell_renderer);
-
-/* cell list manipulation */
-static GList *pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column);
-static GList *pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column);
-static GList *pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
- GList *current);
-static GList *pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
- GList *current);
-static void pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
- PsppSheetViewColumnCellInfo *info);
-/* GtkBuildable implementation */
-static void pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface);
-
-static guint tree_column_signals[LAST_SIGNAL] = { 0 };
-
-G_DEFINE_TYPE_WITH_CODE (PsppSheetViewColumn, pspp_sheet_view_column, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
- pspp_sheet_view_column_cell_layout_init)
- G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
- pspp_sheet_view_column_buildable_init))
-
-
-static void
-pspp_sheet_view_column_class_init (PsppSheetViewColumnClass *class)
-{
- GObjectClass *object_class;
-
- object_class = (GObjectClass*) class;
-
- class->clicked = on_pspp_sheet_view_column_button_clicked;
- class->button_press_event = on_pspp_sheet_view_column_button_press_event;
-
- object_class->finalize = pspp_sheet_view_column_finalize;
- object_class->set_property = pspp_sheet_view_column_set_property;
- object_class->get_property = pspp_sheet_view_column_get_property;
-
- tree_column_signals[CLICKED] =
- g_signal_new ("clicked",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PsppSheetViewColumnClass, clicked),
- g_signal_accumulator_true_handled, NULL,
- psppire_marshal_BOOLEAN__VOID,
- G_TYPE_BOOLEAN, 0);
-
- tree_column_signals[POPUP_MENU] =
- g_signal_new ("popup-menu",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- tree_column_signals[QUERY_TOOLTIP] =
- g_signal_new ("query-tooltip",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- 0,
- g_signal_accumulator_true_handled, NULL,
- psppire_marshal_BOOLEAN__OBJECT,
- G_TYPE_BOOLEAN, 1,
- GTK_TYPE_TOOLTIP);
-
- tree_column_signals[BUTTON_PRESS_EVENT] =
- g_signal_new ("button-press-event",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PsppSheetViewColumnClass, button_press_event),
- g_signal_accumulator_true_handled, NULL,
- psppire_marshal_BOOLEAN__BOXED,
- G_TYPE_BOOLEAN, 1,
- GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
-
- g_object_class_install_property (object_class,
- PROP_VISIBLE,
- g_param_spec_boolean ("visible",
- P_("Visible"),
- P_("Whether to display the column"),
- TRUE,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_RESIZABLE,
- g_param_spec_boolean ("resizable",
- P_("Resizable"),
- P_("Column is user-resizable"),
- FALSE,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_WIDTH,
- g_param_spec_int ("width",
- P_("Width"),
- P_("Current width of the column"),
- 0,
- G_MAXINT,
- 0,
- GTK_PARAM_READABLE));
- g_object_class_install_property (object_class,
- PROP_SPACING,
- g_param_spec_int ("spacing",
- P_("Spacing"),
- P_("Space which is inserted between cells"),
- 0,
- G_MAXINT,
- 0,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_FIXED_WIDTH,
- g_param_spec_int ("fixed-width",
- P_("Fixed Width"),
- P_("Current fixed width of the column"),
- 1,
- G_MAXINT,
- 100,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_MIN_WIDTH,
- g_param_spec_int ("min-width",
- P_("Minimum Width"),
- P_("Minimum allowed width of the column"),
- -1,
- G_MAXINT,
- -1,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_MAX_WIDTH,
- g_param_spec_int ("max-width",
- P_("Maximum Width"),
- P_("Maximum allowed width of the column"),
- -1,
- G_MAXINT,
- -1,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_TITLE,
- g_param_spec_string ("title",
- P_("Title"),
- P_("Title to appear in column header"),
- "",
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_EXPAND,
- g_param_spec_boolean ("expand",
- P_("Expand"),
- P_("Column gets share of extra width allocated to the widget"),
- FALSE,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_CLICKABLE,
- g_param_spec_boolean ("clickable",
- P_("Clickable"),
- P_("Whether the header can be clicked"),
- FALSE,
- GTK_PARAM_READWRITE));
-
-
- g_object_class_install_property (object_class,
- PROP_WIDGET,
- g_param_spec_object ("widget",
- P_("Widget"),
- P_("Widget to put in column header button instead of column title"),
- GTK_TYPE_WIDGET,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_ALIGNMENT,
- g_param_spec_float ("alignment",
- P_("Alignment"),
- P_("X Alignment of the column header text or widget"),
- 0.0,
- 1.0,
- 0.0,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_REORDERABLE,
- g_param_spec_boolean ("reorderable",
- P_("Reorderable"),
- P_("Whether the column can be reordered around the headers"),
- FALSE,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_SORT_INDICATOR,
- g_param_spec_boolean ("sort-indicator",
- P_("Sort indicator"),
- P_("Whether to show a sort indicator"),
- FALSE,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_SORT_ORDER,
- g_param_spec_enum ("sort-order",
- P_("Sort order"),
- P_("Sort direction the sort indicator should indicate"),
- GTK_TYPE_SORT_TYPE,
- GTK_SORT_ASCENDING,
- GTK_PARAM_READWRITE));
-
- /**
- * PsppSheetViewColumn:sort-column-id:
- *
- * Logical sort column ID this column sorts on when selected for sorting. Setting the sort column ID makes the column header
- * clickable. Set to %-1 to make the column unsortable.
- *
- * Since: 2.18
- **/
- g_object_class_install_property (object_class,
- PROP_SORT_COLUMN_ID,
- g_param_spec_int ("sort-column-id",
- P_("Sort column ID"),
- P_("Logical sort column ID this column sorts on when selected for sorting"),
- -1,
- G_MAXINT,
- -1,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_QUICK_EDIT,
- g_param_spec_boolean ("quick-edit",
- P_("Quick edit"),
- P_("If true, editing starts upon the first click in the column. If false, the first click selects the column and a second click is needed to begin editing. This has no effect on cells that are not editable."),
- TRUE,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_SELECTED,
- g_param_spec_boolean ("selected",
- P_("Selected"),
- P_("If true, this column is selected as part of a rectangular selection."),
- FALSE,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_SELECTABLE,
- g_param_spec_boolean ("selectable",
- P_("Selectable"),
- P_("If true, this column may be selected as part of a rectangular selection."),
- TRUE,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_ROW_HEAD,
- g_param_spec_boolean ("row-head",
- P_("Row head"),
- P_("If true, this column is a \"row head\", equivalent to a column head. If rectangular selection is enabled, then shift+click and control+click in the column select row ranges and toggle row selection, respectively. The column should ordinarily include a button cell; clicking on the button will select the row (and deselect all other rows)."),
- FALSE,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (object_class,
- PROP_TABBABLE,
- g_param_spec_boolean ("tabbable",
- P_("Tabbable"),
- P_("If true, Tab and Shift+Tab visit this column. If false, Tab and Shift+Tab skip this column."),
- TRUE,
- GTK_PARAM_READWRITE));
-}
-
-
-static void _cell_layout_buildable_custom_tag_end (GtkBuildable *buildable,
- GtkBuilder *builder,
- GObject *child,
- const gchar *tagname,
- gpointer *data);
-
-
-static void _cell_layout_buildable_add_child (GtkBuildable *buildable,
- GtkBuilder *builder,
- GObject *child,
- const gchar *type);
-
-
-static gboolean _cell_layout_buildable_custom_tag_start (GtkBuildable *buildable,
- GtkBuilder *builder,
- GObject *child,
- const gchar *tagname,
- GMarkupParser *parser,
- gpointer *data);
-
-
-static void
-pspp_sheet_view_column_buildable_init (GtkBuildableIface *iface)
-{
- iface->add_child = _cell_layout_buildable_add_child;
- iface->custom_tag_start = _cell_layout_buildable_custom_tag_start;
- iface->custom_tag_end = _cell_layout_buildable_custom_tag_end;
-}
-
-static void
-pspp_sheet_view_column_cell_layout_init (GtkCellLayoutIface *iface)
-{
- iface->pack_start = pspp_sheet_view_column_cell_layout_pack_start;
- iface->pack_end = pspp_sheet_view_column_cell_layout_pack_end;
- iface->clear = pspp_sheet_view_column_cell_layout_clear;
- iface->add_attribute = pspp_sheet_view_column_cell_layout_add_attribute;
- iface->set_cell_data_func = pspp_sheet_view_column_cell_layout_set_cell_data_func;
- iface->clear_attributes = pspp_sheet_view_column_cell_layout_clear_attributes;
- iface->reorder = pspp_sheet_view_column_cell_layout_reorder;
- iface->get_cells = pspp_sheet_view_column_cell_layout_get_cells;
-}
-
-static void
-pspp_sheet_view_column_init (PsppSheetViewColumn *tree_column)
-{
- tree_column->button = NULL;
- tree_column->halign = GTK_ALIGN_START;
- tree_column->width = 0;
- tree_column->spacing = 0;
- tree_column->requested_width = -1;
- tree_column->min_width = -1;
- tree_column->max_width = -1;
- tree_column->resized_width = 0;
- tree_column->visible = TRUE;
- tree_column->resizable = FALSE;
- tree_column->expand = FALSE;
- tree_column->clickable = FALSE;
- tree_column->dirty = TRUE;
- tree_column->selected = FALSE;
- tree_column->selectable = TRUE;
- tree_column->row_head = FALSE;
- tree_column->tabbable = TRUE;
- tree_column->sort_order = GTK_SORT_ASCENDING;
- tree_column->show_sort_indicator = FALSE;
- tree_column->property_changed_signal = 0;
- tree_column->sort_clicked_signal = 0;
- tree_column->sort_column_changed_signal = 0;
- tree_column->sort_column_id = -1;
- tree_column->reorderable = FALSE;
- tree_column->maybe_reordered = FALSE;
- tree_column->fixed_width = 1;
- tree_column->use_resized_width = FALSE;
- tree_column->title = g_strdup ("");
- tree_column->quick_edit = TRUE;
-}
-
-static void
-pspp_sheet_view_column_finalize (GObject *object)
-{
- PsppSheetViewColumn *tree_column = (PsppSheetViewColumn *) object;
- GList *list;
-
- for (list = tree_column->cell_list; list; list = list->next)
- {
- PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
-
- if (info->destroy)
- {
- GDestroyNotify d = info->destroy;
-
- info->destroy = NULL;
- d (info->func_data);
- }
- pspp_sheet_view_column_clear_attributes_by_info (tree_column, info);
- g_object_unref (info->cell);
- g_free (info);
- }
-
- g_free (tree_column->title);
- g_list_free (tree_column->cell_list);
-
- if (tree_column->child)
- g_object_unref (tree_column->child);
-
- G_OBJECT_CLASS (pspp_sheet_view_column_parent_class)->finalize (object);
-}
-
-static void
-pspp_sheet_view_column_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- PsppSheetViewColumn *tree_column;
-
- tree_column = PSPP_SHEET_VIEW_COLUMN (object);
-
- switch (prop_id)
- {
- case PROP_VISIBLE:
- pspp_sheet_view_column_set_visible (tree_column,
- g_value_get_boolean (value));
- break;
-
- case PROP_RESIZABLE:
- pspp_sheet_view_column_set_resizable (tree_column,
- g_value_get_boolean (value));
- break;
-
- case PROP_FIXED_WIDTH:
- pspp_sheet_view_column_set_fixed_width (tree_column,
- g_value_get_int (value));
- break;
-
- case PROP_MIN_WIDTH:
- pspp_sheet_view_column_set_min_width (tree_column,
- g_value_get_int (value));
- break;
-
- case PROP_MAX_WIDTH:
- pspp_sheet_view_column_set_max_width (tree_column,
- g_value_get_int (value));
- break;
-
- case PROP_SPACING:
- pspp_sheet_view_column_set_spacing (tree_column,
- g_value_get_int (value));
- break;
-
- case PROP_TITLE:
- pspp_sheet_view_column_set_title (tree_column,
- g_value_get_string (value));
- break;
-
- case PROP_EXPAND:
- pspp_sheet_view_column_set_expand (tree_column,
- g_value_get_boolean (value));
- break;
-
- case PROP_CLICKABLE:
- pspp_sheet_view_column_set_clickable (tree_column,
- g_value_get_boolean (value));
- break;
-
- case PROP_WIDGET:
- pspp_sheet_view_column_set_widget (tree_column,
- (GtkWidget*) g_value_get_object (value));
- break;
-
- case PROP_ALIGNMENT:
- pspp_sheet_view_column_set_alignment (tree_column,
- g_value_get_float (value));
- break;
-
- case PROP_REORDERABLE:
- pspp_sheet_view_column_set_reorderable (tree_column,
- g_value_get_boolean (value));
- break;
-
- case PROP_SORT_INDICATOR:
- pspp_sheet_view_column_set_sort_indicator (tree_column,
- g_value_get_boolean (value));
- break;
-
- case PROP_SORT_ORDER:
- pspp_sheet_view_column_set_sort_order (tree_column,
- g_value_get_enum (value));
- break;
-
- case PROP_SORT_COLUMN_ID:
- pspp_sheet_view_column_set_sort_column_id (tree_column,
- g_value_get_int (value));
- break;
-
- case PROP_QUICK_EDIT:
- pspp_sheet_view_column_set_quick_edit (tree_column,
- g_value_get_boolean (value));
- break;
-
- case PROP_SELECTED:
- pspp_sheet_view_column_set_selected (tree_column,
- g_value_get_boolean (value));
- break;
-
- case PROP_SELECTABLE:
- pspp_sheet_view_column_set_selectable (tree_column,
- g_value_get_boolean (value));
- break;
-
- case PROP_ROW_HEAD:
- pspp_sheet_view_column_set_row_head (tree_column,
- g_value_get_boolean (value));
- break;
-
- case PROP_TABBABLE:
- pspp_sheet_view_column_set_tabbable (tree_column,
- g_value_get_boolean (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-pspp_sheet_view_column_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- PsppSheetViewColumn *tree_column;
-
- tree_column = PSPP_SHEET_VIEW_COLUMN (object);
-
- switch (prop_id)
- {
- case PROP_VISIBLE:
- g_value_set_boolean (value,
- pspp_sheet_view_column_get_visible (tree_column));
- break;
-
- case PROP_RESIZABLE:
- g_value_set_boolean (value,
- pspp_sheet_view_column_get_resizable (tree_column));
- break;
-
- case PROP_WIDTH:
- g_value_set_int (value,
- pspp_sheet_view_column_get_width (tree_column));
- break;
-
- case PROP_SPACING:
- g_value_set_int (value,
- pspp_sheet_view_column_get_spacing (tree_column));
- break;
-
- case PROP_FIXED_WIDTH:
- g_value_set_int (value,
- pspp_sheet_view_column_get_fixed_width (tree_column));
- break;
-
- case PROP_MIN_WIDTH:
- g_value_set_int (value,
- pspp_sheet_view_column_get_min_width (tree_column));
- break;
-
- case PROP_MAX_WIDTH:
- g_value_set_int (value,
- pspp_sheet_view_column_get_max_width (tree_column));
- break;
-
- case PROP_TITLE:
- g_value_set_string (value,
- pspp_sheet_view_column_get_title (tree_column));
- break;
-
- case PROP_EXPAND:
- g_value_set_boolean (value,
- pspp_sheet_view_column_get_expand (tree_column));
- break;
-
- case PROP_CLICKABLE:
- g_value_set_boolean (value,
- pspp_sheet_view_column_get_clickable (tree_column));
- break;
-
- case PROP_WIDGET:
- g_value_set_object (value,
- (GObject*) pspp_sheet_view_column_get_widget (tree_column));
- break;
-
- case PROP_ALIGNMENT:
- g_value_set_float (value,
- pspp_sheet_view_column_get_alignment (tree_column));
- break;
-
- case PROP_REORDERABLE:
- g_value_set_boolean (value,
- pspp_sheet_view_column_get_reorderable (tree_column));
- break;
-
- case PROP_SORT_INDICATOR:
- g_value_set_boolean (value,
- pspp_sheet_view_column_get_sort_indicator (tree_column));
- break;
-
- case PROP_SORT_ORDER:
- g_value_set_enum (value,
- pspp_sheet_view_column_get_sort_order (tree_column));
- break;
-
- case PROP_SORT_COLUMN_ID:
- g_value_set_int (value,
- pspp_sheet_view_column_get_sort_column_id (tree_column));
- break;
-
- case PROP_QUICK_EDIT:
- g_value_set_boolean (value,
- pspp_sheet_view_column_get_quick_edit (tree_column));
- break;
-
- case PROP_SELECTED:
- g_value_set_boolean (value,
- pspp_sheet_view_column_get_selected (tree_column));
- break;
-
- case PROP_SELECTABLE:
- g_value_set_boolean (value,
- pspp_sheet_view_column_get_selectable (tree_column));
- break;
-
- case PROP_ROW_HEAD:
- g_value_set_boolean (value,
- pspp_sheet_view_column_get_row_head (tree_column));
- break;
-
- case PROP_TABBABLE:
- g_value_set_boolean (value,
- pspp_sheet_view_column_get_tabbable (tree_column));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-/* Implementation of GtkCellLayout interface
- */
-
-static void
-pspp_sheet_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
- GtkCellRenderer *cell,
- gboolean expand)
-{
- PsppSheetViewColumn *column;
- PsppSheetViewColumnCellInfo *cell_info;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
- column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
- g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
-
- g_object_ref_sink (cell);
-
- cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
- cell_info->cell = cell;
- cell_info->expand = expand ? TRUE : FALSE;
- cell_info->pack = GTK_PACK_START;
- cell_info->has_focus = 0;
- cell_info->attributes = NULL;
-
- column->cell_list = g_list_append (column->cell_list, cell_info);
-}
-
-static void
-pspp_sheet_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
- GtkCellRenderer *cell,
- gboolean expand)
-{
- PsppSheetViewColumn *column;
- PsppSheetViewColumnCellInfo *cell_info;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
- column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
- g_return_if_fail (! pspp_sheet_view_column_get_cell_info (column, cell));
-
- g_object_ref_sink (cell);
-
- cell_info = g_new0 (PsppSheetViewColumnCellInfo, 1);
- cell_info->cell = cell;
- cell_info->expand = expand ? TRUE : FALSE;
- cell_info->pack = GTK_PACK_END;
- cell_info->has_focus = 0;
- cell_info->attributes = NULL;
-
- column->cell_list = g_list_append (column->cell_list, cell_info);
-}
-
-static void
-pspp_sheet_view_column_cell_layout_clear (GtkCellLayout *cell_layout)
-{
- PsppSheetViewColumn *column;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
- column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
-
- while (column->cell_list)
- {
- PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)column->cell_list->data;
-
- pspp_sheet_view_column_cell_layout_clear_attributes (cell_layout, info->cell);
- g_object_unref (info->cell);
- g_free (info);
- column->cell_list = g_list_delete_link (column->cell_list,
- column->cell_list);
- }
-}
-
-static void
-pspp_sheet_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
- GtkCellRenderer *cell,
- const gchar *attribute,
- gint column)
-{
- PsppSheetViewColumn *tree_column;
- PsppSheetViewColumnCellInfo *info;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
- tree_column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
-
- info = pspp_sheet_view_column_get_cell_info (tree_column, cell);
- g_return_if_fail (info != NULL);
-
- info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column));
- info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
-
- if (tree_column->tree_view)
- _pspp_sheet_view_column_cell_set_dirty (tree_column);
-}
-
-static void
-pspp_sheet_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
- GtkCellRenderer *cell,
- GtkCellLayoutDataFunc func,
- gpointer func_data,
- GDestroyNotify destroy)
-{
- PsppSheetViewColumn *column;
- PsppSheetViewColumnCellInfo *info;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
- column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
-
- info = pspp_sheet_view_column_get_cell_info (column, cell);
- g_return_if_fail (info != NULL);
-
- if (info->destroy)
- {
- GDestroyNotify d = info->destroy;
-
- info->destroy = NULL;
- d (info->func_data);
- }
-
- info->func = (PsppSheetCellDataFunc)func;
- info->func_data = func_data;
- info->destroy = destroy;
-
- if (column->tree_view)
- _pspp_sheet_view_column_cell_set_dirty (column);
-}
-
-static void
-pspp_sheet_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
- GtkCellRenderer *cell_renderer)
-{
- PsppSheetViewColumn *column;
- PsppSheetViewColumnCellInfo *info;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
- column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
-
- info = pspp_sheet_view_column_get_cell_info (column, cell_renderer);
- if (info)
- pspp_sheet_view_column_clear_attributes_by_info (column, info);
-}
-
-static void
-pspp_sheet_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
- GtkCellRenderer *cell,
- gint position)
-{
- GList *link;
- PsppSheetViewColumn *column;
- PsppSheetViewColumnCellInfo *info;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (cell_layout));
- column = PSPP_SHEET_VIEW_COLUMN (cell_layout);
-
- info = pspp_sheet_view_column_get_cell_info (column, cell);
-
- g_return_if_fail (info != NULL);
- g_return_if_fail (position >= 0);
-
- link = g_list_find (column->cell_list, info);
-
- g_return_if_fail (link != NULL);
-
- column->cell_list = g_list_delete_link (column->cell_list, link);
- column->cell_list = g_list_insert (column->cell_list, info, position);
-
- if (column->tree_view)
- gtk_widget_queue_draw (column->tree_view);
-}
-
-static void
-pspp_sheet_view_column_clear_attributes_by_info (PsppSheetViewColumn *tree_column,
- PsppSheetViewColumnCellInfo *info)
-{
- GSList *list;
-
- list = info->attributes;
-
- while (list && list->next)
- {
- g_free (list->data);
- list = list->next->next;
- }
- g_slist_free (info->attributes);
- info->attributes = NULL;
-
- if (tree_column->tree_view)
- _pspp_sheet_view_column_cell_set_dirty (tree_column);
-}
-
-static gboolean
-on_query_tooltip (GtkWidget *widget,
- gint x,
- gint y,
- gboolean keyboard_mode,
- GtkTooltip *tooltip,
- gpointer user_data)
-{
- PsppSheetViewColumn *tree_column = user_data;
- gboolean handled;
-
- g_signal_emit (tree_column, tree_column_signals[QUERY_TOOLTIP], 0,
- tooltip, &handled);
- return handled;
-}
-
-static gboolean
-on_button_pressed (GtkWidget *widget, GdkEventButton *event,
- gpointer user_data)
-{
- PsppSheetViewColumn *tree_column = user_data;
- gboolean handled;
-
- /* XXX See "Implement GtkWidget::popup_menu" in GTK+ reference manual. */
- g_signal_emit (tree_column, tree_column_signals[BUTTON_PRESS_EVENT],
- 0, event, &handled);
- return handled;
-}
-
-/* Helper functions
- */
-
-/* Button handling code
- */
-static void
-pspp_sheet_view_column_create_button (PsppSheetViewColumn *tree_column)
-{
- PsppSheetView *tree_view;
- GtkWidget *child;
- GtkWidget *hbox;
-
- tree_view = (PsppSheetView *) tree_column->tree_view;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
- g_return_if_fail (tree_column->button == NULL);
-
- tree_column->button = gtk_button_new ();
- gtk_widget_add_events (tree_column->button, GDK_POINTER_MOTION_MASK);
-
- /* make sure we own a reference to it as well. */
- if (tree_view->priv->header_window)
- gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window);
- gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
-
- g_signal_connect (tree_column->button, "event",
- G_CALLBACK (pspp_sheet_view_column_button_event),
- tree_column);
- g_signal_connect (tree_column->button, "clicked",
- G_CALLBACK (pspp_sheet_view_column_button_clicked),
- tree_column);
- g_signal_connect (tree_column->button, "popup-menu",
- G_CALLBACK (pspp_sheet_view_column_button_popup_menu),
- tree_column);
- g_signal_connect (tree_column->button, "button-press-event",
- G_CALLBACK (on_button_pressed), tree_column);
-
- g_signal_connect (tree_column->button, "query-tooltip",
- G_CALLBACK (on_query_tooltip), tree_column);
- g_object_set (tree_column->button, "has-tooltip", TRUE, NULL);
-
- tree_column->bin = gtk_event_box_new ();
- g_object_set (tree_column->bin, "halign", GTK_ALIGN_CENTER, NULL);
-
- hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
-
- if (tree_column->child)
- child = tree_column->child;
- else
- {
- child = gtk_label_new (tree_column->title);
- gtk_widget_show (child);
- }
-
- g_signal_connect (child, "mnemonic-activate",
- G_CALLBACK (pspp_sheet_view_column_mnemonic_activate),
- tree_column);
-
-
- gtk_box_pack_start (GTK_BOX (hbox), tree_column->bin, TRUE, TRUE, 0);
-
- gtk_container_add (GTK_CONTAINER (tree_column->bin), child);
- gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);
-
- gtk_widget_show (hbox);
- gtk_widget_show (tree_column->bin);
- pspp_sheet_view_column_update_button (tree_column);
-}
-
-void
-pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column)
-{
- gint sort_column_id = -1;
- GtkWidget *alignment;
- GtkWidget *current_child;
- GtkTreeModel *model;
- gboolean can_focus;
-
- if (tree_column->tree_view)
- model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
- else
- model = NULL;
-
- /* Create a button if necessary */
- if (tree_column->visible &&
- tree_column->button == NULL &&
- tree_column->tree_view &&
- gtk_widget_get_realized (tree_column->tree_view))
- pspp_sheet_view_column_create_button (tree_column);
-
- if (! tree_column->button)
- return;
-
- alignment = tree_column->bin;
- current_child = gtk_bin_get_child (GTK_BIN (alignment));
-
- /* Set up the actual button */
- g_object_set (alignment,
- "halign", tree_column->halign,
- "valign", GTK_ALIGN_CENTER, NULL);
-
- if (tree_column->child)
- {
- if (current_child != tree_column->child)
- {
- gtk_container_remove (GTK_CONTAINER (alignment),
- current_child);
- gtk_container_add (GTK_CONTAINER (alignment),
- tree_column->child);
- }
- }
- else
- {
- if (current_child == NULL)
- {
- current_child = gtk_label_new (NULL);
- gtk_widget_show (current_child);
- gtk_container_add (GTK_CONTAINER (alignment),
- current_child);
- }
-
- g_return_if_fail (GTK_IS_LABEL (current_child));
-
- if (tree_column->title)
- gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
- tree_column->title);
- else
- gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
- "");
- }
-
- if (GTK_IS_TREE_SORTABLE (model))
- gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
- &sort_column_id,
- NULL);
-
-
- /* It's always safe to hide the button. It isn't always safe to show it, as
- * if you show it before it's realized, it'll get the wrong window. */
- if (tree_column->button &&
- tree_column->tree_view != NULL &&
- gtk_widget_get_realized (tree_column->tree_view))
- {
- if (tree_column->visible)
- {
- gtk_widget_show (tree_column->button);
- if (tree_column->window)
- {
- if (tree_column->resizable)
- {
- gdk_window_show (tree_column->window);
- gdk_window_raise (tree_column->window);
- }
- else
- {
- gdk_window_hide (tree_column->window);
- }
- }
- }
- else
- {
- gtk_widget_hide (tree_column->button);
- if (tree_column->window)
- gdk_window_hide (tree_column->window);
- }
- }
-
- can_focus = pspp_sheet_view_column_can_focus (tree_column);
- gtk_widget_set_can_focus (tree_column->button, can_focus);
- if (!can_focus && gtk_widget_has_focus (tree_column->button))
- {
- GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view);
- if (gtk_widget_is_toplevel (toplevel))
- {
- gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
- }
- }
-
- /* Queue a resize on the assumption that we always want to catch all changes
- * and columns don't change all that often.
- */
- if (gtk_widget_get_realized (tree_column->tree_view))
- gtk_widget_queue_resize (tree_column->tree_view);
-
-}
-
-/* Button signal handlers
- */
-
-static gint
-pspp_sheet_view_column_button_event (GtkWidget *widget,
- GdkEventButton *event,
- gpointer data)
-{
- PsppSheetViewColumn *column = (PsppSheetViewColumn *) data;
-
- g_return_val_if_fail (event != NULL, FALSE);
-
- if (event->type == GDK_BUTTON_PRESS &&
- column->reorderable &&
- ((GdkEventButton *)event)->button == 1)
- {
- column->maybe_reordered = TRUE;
- gdk_window_get_device_position (gtk_button_get_event_window (GTK_BUTTON (widget)),
- event->device,
- &column->drag_x,
- &column->drag_y,
- NULL);
- gtk_widget_grab_focus (widget);
- }
-
- if (event->type == GDK_BUTTON_RELEASE ||
- event->type == GDK_LEAVE_NOTIFY)
- column->maybe_reordered = FALSE;
-
- if (event->type == GDK_MOTION_NOTIFY &&
- column->maybe_reordered &&
- (gtk_drag_check_threshold (widget,
- column->drag_x,
- column->drag_y,
- (gint) ((GdkEventMotion *)event)->x,
- (gint) ((GdkEventMotion *)event)->y)))
- {
- column->maybe_reordered = FALSE;
- _pspp_sheet_view_column_start_drag (PSPP_SHEET_VIEW (column->tree_view), column);
- return TRUE;
- }
- if (column->clickable == FALSE)
- {
- switch (event->type)
- {
- case GDK_MOTION_NOTIFY:
- case GDK_BUTTON_RELEASE:
- case GDK_ENTER_NOTIFY:
- case GDK_LEAVE_NOTIFY:
- return TRUE;
- default:
- return FALSE;
- }
- }
- return FALSE;
-}
-
-static gboolean
-all_rows_selected (PsppSheetView *sheet_view)
-{
- PsppSheetSelection *selection = sheet_view->priv->selection;
- gint n_rows, n_selected_rows;
-
- n_rows = sheet_view->priv->row_count;
- n_selected_rows = pspp_sheet_selection_count_selected_rows (selection);
-
- return n_rows > 0 && n_selected_rows >= n_rows;
-}
-
-static gboolean
-on_pspp_sheet_view_column_button_press_event (PsppSheetViewColumn *column,
- GdkEventButton *event)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (column->tree_view);
- PsppSheetSelection *selection;
- GSignalInvocationHint *hint;
- guint modifiers;
-
- /* We only want to run first, not last, but combining that with return type
- `gboolean' makes GObject warn, so just ignore the run_last call. */
- hint = g_signal_get_invocation_hint (column);
- g_return_val_if_fail (hint != NULL, FALSE);
- if (hint->run_type != G_SIGNAL_RUN_FIRST)
- return FALSE;
-
- g_return_val_if_fail (sheet_view != NULL, FALSE);
-
- selection = sheet_view->priv->selection;
- g_return_val_if_fail (selection != NULL, FALSE);
-
- if (pspp_sheet_selection_get_mode (selection) != PSPP_SHEET_SELECTION_RECTANGLE)
- return FALSE;
-
- modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
- if (event->type == GDK_BUTTON_PRESS && event->button == 3)
- {
- if (pspp_sheet_selection_count_selected_columns (selection) <= 1
- || !all_rows_selected (sheet_view))
- {
- pspp_sheet_selection_select_all (selection);
- pspp_sheet_selection_unselect_all_columns (selection);
- pspp_sheet_selection_select_column (selection, column);
- sheet_view->priv->anchor_column = column;
- }
- return FALSE;
- }
- else if (event->type == GDK_BUTTON_PRESS && event->button == 1
- && modifiers == GDK_CONTROL_MASK)
- {
- gboolean is_selected;
-
- if (!all_rows_selected (sheet_view))
- {
- pspp_sheet_selection_select_all (selection);
- pspp_sheet_selection_unselect_all_columns (selection);
- }
- sheet_view->priv->anchor_column = column;
-
- is_selected = pspp_sheet_view_column_get_selected (column);
- pspp_sheet_view_column_set_selected (column, !is_selected);
-
- return TRUE;
- }
- else if (event->type == GDK_BUTTON_PRESS && event->button == 1
- && modifiers == GDK_SHIFT_MASK)
- {
- if (!all_rows_selected (sheet_view))
- {
- pspp_sheet_selection_select_all (selection);
- pspp_sheet_selection_unselect_all_columns (selection);
- sheet_view->priv->anchor_column = column;
- }
- else if (sheet_view->priv->anchor_column == NULL)
- sheet_view->priv->anchor_column = column;
-
- pspp_sheet_selection_unselect_all_columns (selection);
- pspp_sheet_selection_select_column_range (selection,
- sheet_view->priv->anchor_column,
- column);
- return TRUE;
- }
-
- return FALSE;
-}
-
-static gboolean
-on_pspp_sheet_view_column_button_clicked (PsppSheetViewColumn *column)
-{
- PsppSheetSelection *selection;
- PsppSheetView *sheet_view;
-
- sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (column));
- selection = pspp_sheet_view_get_selection (sheet_view);
- if (pspp_sheet_selection_get_mode (selection) == PSPP_SHEET_SELECTION_RECTANGLE)
- {
- pspp_sheet_selection_select_all (selection);
- if (pspp_sheet_view_column_get_row_head (column))
- pspp_sheet_selection_select_all_columns (selection);
- else
- {
- pspp_sheet_selection_unselect_all_columns (selection);
- pspp_sheet_selection_select_column (selection, column);
- }
- sheet_view->priv->anchor_column = column;
- return TRUE;
- }
- return FALSE;
-}
-
-static void
-pspp_sheet_view_column_button_clicked (GtkWidget *widget, gpointer data)
-{
- PsppSheetViewColumn *column = data;
- gboolean handled;
-
- g_signal_emit (column, tree_column_signals[CLICKED], 0, &handled);
-}
-
-static void
-pspp_sheet_view_column_button_popup_menu (GtkWidget *widget, gpointer data)
-{
- g_signal_emit_by_name (data, "popup-menu");
-}
-
-static gboolean
-pspp_sheet_view_column_mnemonic_activate (GtkWidget *widget,
- gboolean group_cycling,
- gpointer data)
-{
- PsppSheetViewColumn *column = (PsppSheetViewColumn *)data;
-
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column), FALSE);
-
- PSPP_SHEET_VIEW (column->tree_view)->priv->focus_column = column;
- if (column->clickable)
- gtk_button_clicked (GTK_BUTTON (column->button));
- else if (gtk_widget_get_can_focus (column->button))
- gtk_widget_grab_focus (column->button);
- else
- gtk_widget_grab_focus (column->tree_view);
-
- return TRUE;
-}
-
-static void
-pspp_sheet_view_model_sort_column_changed (GtkTreeSortable *sortable,
- PsppSheetViewColumn *column)
-{
- gint sort_column_id;
- GtkSortType order;
-
- if (gtk_tree_sortable_get_sort_column_id (sortable,
- &sort_column_id,
- &order))
- {
- if (sort_column_id == column->sort_column_id)
- {
- pspp_sheet_view_column_set_sort_indicator (column, TRUE);
- pspp_sheet_view_column_set_sort_order (column, order);
- }
- else
- {
- pspp_sheet_view_column_set_sort_indicator (column, FALSE);
- }
- }
- else
- {
- pspp_sheet_view_column_set_sort_indicator (column, FALSE);
- }
-}
-
-static void
-pspp_sheet_view_column_sort (PsppSheetViewColumn *tree_column,
- gpointer data)
-{
- gint sort_column_id;
- GtkSortType order;
- gboolean has_sort_column;
- gboolean has_default_sort_func;
-
- g_return_if_fail (tree_column->tree_view != NULL);
-
- has_sort_column =
- gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
- &sort_column_id,
- &order);
- has_default_sort_func =
- gtk_tree_sortable_has_default_sort_func (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model));
-
- if (has_sort_column &&
- sort_column_id == tree_column->sort_column_id)
- {
- if (order == GTK_SORT_ASCENDING)
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
- tree_column->sort_column_id,
- GTK_SORT_DESCENDING);
- else if (order == GTK_SORT_DESCENDING && has_default_sort_func)
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
- GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
- GTK_SORT_ASCENDING);
- else
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
- tree_column->sort_column_id,
- GTK_SORT_ASCENDING);
- }
- else
- {
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->model),
- tree_column->sort_column_id,
- GTK_SORT_ASCENDING);
- }
-}
-
-
-static void
-pspp_sheet_view_column_setup_sort_column_id_callback (PsppSheetViewColumn *tree_column)
-{
- GtkTreeModel *model;
-
- if (tree_column->tree_view == NULL)
- return;
-
- model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
-
- if (model == NULL)
- return;
-
- if (GTK_IS_TREE_SORTABLE (model) &&
- tree_column->sort_column_id != -1)
- {
- gint real_sort_column_id;
- GtkSortType real_order;
-
- if (tree_column->sort_column_changed_signal == 0)
- tree_column->sort_column_changed_signal =
- g_signal_connect (model, "sort-column-changed",
- G_CALLBACK (pspp_sheet_view_model_sort_column_changed),
- tree_column);
-
- if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
- &real_sort_column_id,
- &real_order) &&
- (real_sort_column_id == tree_column->sort_column_id))
- {
- pspp_sheet_view_column_set_sort_indicator (tree_column, TRUE);
- pspp_sheet_view_column_set_sort_order (tree_column, real_order);
- }
- else
- {
- pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
- }
- }
-}
-
-
-/* Exported Private Functions.
- * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
- */
-
-void
-_pspp_sheet_view_column_realize_button (PsppSheetViewColumn *column)
-{
- GtkAllocation allocation;
- PsppSheetView *tree_view;
- GdkWindowAttr attr;
- guint attributes_mask;
- gboolean rtl;
-
- tree_view = (PsppSheetView *)column->tree_view;
- rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
- g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
- g_return_if_fail (tree_view->priv->header_window != NULL);
- if (!column->button)
- return;
-
- g_return_if_fail (column->button != NULL);
-
- gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
-
- if (column->visible)
- gtk_widget_show (column->button);
-
- attr.window_type = GDK_WINDOW_CHILD;
- attr.wclass = GDK_INPUT_ONLY;
- attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
- attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view)) |
- (GDK_BUTTON_PRESS_MASK |
- GDK_BUTTON_RELEASE_MASK |
- GDK_POINTER_MOTION_MASK |
- GDK_POINTER_MOTION_HINT_MASK |
- GDK_KEY_PRESS_MASK);
- attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
- attr.cursor = gdk_cursor_new_for_display (gdk_window_get_display (tree_view->priv->header_window),
- GDK_SB_H_DOUBLE_ARROW);
- attr.y = 0;
- attr.width = TREE_VIEW_DRAG_WIDTH;
- attr.height = tree_view->priv->header_height;
- gtk_widget_get_allocation (column->button, &allocation);
- attr.x = (allocation.x + (rtl ? 0 : allocation.width)) - TREE_VIEW_DRAG_WIDTH / 2;
- column->window = gdk_window_new (tree_view->priv->header_window,
- &attr, attributes_mask);
- gdk_window_set_user_data (column->window, tree_view);
-
- pspp_sheet_view_column_update_button (column);
-
- g_object_unref (attr.cursor);
-}
-
-void
-_pspp_sheet_view_column_unrealize_button (PsppSheetViewColumn *column)
-{
- g_return_if_fail (column != NULL);
- if (column->window != NULL)
- {
- gdk_window_set_user_data (column->window, NULL);
- gdk_window_destroy (column->window);
- column->window = NULL;
- }
-}
-
-void
-_pspp_sheet_view_column_unset_model (PsppSheetViewColumn *column,
- GtkTreeModel *old_model)
-{
- if (column->sort_column_changed_signal)
- {
- g_signal_handler_disconnect (old_model,
- column->sort_column_changed_signal);
- column->sort_column_changed_signal = 0;
- }
- pspp_sheet_view_column_set_sort_indicator (column, FALSE);
-}
-
-void
-_pspp_sheet_view_column_set_tree_view (PsppSheetViewColumn *column,
- PsppSheetView *tree_view)
-{
- g_assert (column->tree_view == NULL);
-
- column->tree_view = GTK_WIDGET (tree_view);
- pspp_sheet_view_column_create_button (column);
-
- column->property_changed_signal =
- g_signal_connect_swapped (tree_view,
- "notify::model",
- G_CALLBACK (pspp_sheet_view_column_setup_sort_column_id_callback),
- column);
-
- pspp_sheet_view_column_setup_sort_column_id_callback (column);
-}
-
-void
-_pspp_sheet_view_column_unset_tree_view (PsppSheetViewColumn *column)
-{
- if (column->tree_view && column->button)
- {
- gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
- }
- if (column->property_changed_signal)
- {
- g_signal_handler_disconnect (column->tree_view, column->property_changed_signal);
- column->property_changed_signal = 0;
- }
-
- if (column->sort_column_changed_signal)
- {
- g_signal_handler_disconnect (pspp_sheet_view_get_model (PSPP_SHEET_VIEW (column->tree_view)),
- column->sort_column_changed_signal);
- column->sort_column_changed_signal = 0;
- }
-
- column->tree_view = NULL;
- column->button = NULL;
-}
-
-gboolean
-_pspp_sheet_view_column_has_editable_cell (PsppSheetViewColumn *column)
-{
- GList *list;
-
- for (list = column->cell_list; list; list = list->next)
- {
- GtkCellRendererMode mode;
- g_object_get (((PsppSheetViewColumnCellInfo *)list->data)->cell, "mode", &mode, NULL);
- if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
- return TRUE;
- }
-
- return FALSE;
-}
-
-/* gets cell being edited */
-GtkCellRenderer *
-_pspp_sheet_view_column_get_edited_cell (PsppSheetViewColumn *column)
-{
- GList *list;
-
- for (list = column->cell_list; list; list = list->next)
- if (((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode)
- return ((PsppSheetViewColumnCellInfo *)list->data)->cell;
-
- return NULL;
-}
-
-gint
-_pspp_sheet_view_column_count_special_cells (PsppSheetViewColumn *column)
-{
- gint i = 0;
- GList *list;
-
- for (list = column->cell_list; list; list = list->next)
- {
- PsppSheetViewColumnCellInfo *cellinfo = list->data;
-
- GtkCellRendererMode mode;
- g_object_get (cellinfo->cell, "mode", &mode, NULL);
-
- if ((mode == GTK_CELL_RENDERER_MODE_EDITABLE ||
- mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE) &&
- gtk_cell_renderer_get_visible (cellinfo->cell))
- i++;
- }
-
- return i;
-}
-
-GtkCellRenderer *
-_pspp_sheet_view_column_get_cell_at_pos (PsppSheetViewColumn *column,
- gint x)
-{
- GList *list;
- gint current_x = 0;
-
- list = pspp_sheet_view_column_cell_first (column);
- for (; list; list = pspp_sheet_view_column_cell_next (column, list))
- {
- PsppSheetViewColumnCellInfo *cellinfo = list->data;
- if (current_x <= x && x <= current_x + cellinfo->real_width)
- return cellinfo->cell;
- current_x += cellinfo->real_width;
- }
-
- return NULL;
-}
-
-/* Public Functions */
-
-
-/**
- * pspp_sheet_view_column_new:
- *
- * Creates a new #PsppSheetViewColumn.
- *
- * Return value: A newly created #PsppSheetViewColumn.
- **/
-PsppSheetViewColumn *
-pspp_sheet_view_column_new (void)
-{
- PsppSheetViewColumn *tree_column;
-
- tree_column = g_object_new (PSPP_TYPE_SHEET_VIEW_COLUMN, NULL);
-
- return tree_column;
-}
-
-/**
- * pspp_sheet_view_column_new_with_attributes:
- * @title: The title to set the header to.
- * @cell: The #GtkCellRenderer.
- * @Varargs: A %NULL-terminated list of attributes.
- *
- * Creates a new #PsppSheetViewColumn with a number of default values. This is
- * equivalent to calling pspp_sheet_view_column_set_title(),
- * pspp_sheet_view_column_pack_start(), and
- * pspp_sheet_view_column_set_attributes() on the newly created #PsppSheetViewColumn.
- *
- * Here's a simple example:
- * |[
- * enum { TEXT_COLUMN, COLOR_COLUMN, N_COLUMNS };
- * ...
- * {
- * PsppSheetViewColumn *column;
- * GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
- *
- * column = pspp_sheet_view_column_new_with_attributes ("Title",
- * renderer,
- * "text", TEXT_COLUMN,
- * "foreground", COLOR_COLUMN,
- * NULL);
- * }
- * ]|
- *
- * Return value: A newly created #PsppSheetViewColumn.
- **/
-PsppSheetViewColumn *
-pspp_sheet_view_column_new_with_attributes (const gchar *title,
- GtkCellRenderer *cell,
- ...)
-{
- PsppSheetViewColumn *retval;
- va_list args;
-
- retval = pspp_sheet_view_column_new ();
-
- pspp_sheet_view_column_set_title (retval, title);
- pspp_sheet_view_column_pack_start (retval, cell, TRUE);
-
- va_start (args, cell);
- pspp_sheet_view_column_set_attributesv (retval, cell, args);
- va_end (args);
-
- return retval;
-}
-
-static PsppSheetViewColumnCellInfo *
-pspp_sheet_view_column_get_cell_info (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell_renderer)
-{
- GList *list;
- for (list = tree_column->cell_list; list; list = list->next)
- if (((PsppSheetViewColumnCellInfo *)list->data)->cell == cell_renderer)
- return (PsppSheetViewColumnCellInfo *) list->data;
- return NULL;
-}
-
-
-/**
- * pspp_sheet_view_column_pack_start:
- * @tree_column: A #PsppSheetViewColumn.
- * @cell: The #GtkCellRenderer.
- * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
- *
- * Packs the @cell into the beginning of the column. If @expand is %FALSE, then
- * the @cell is allocated no more space than it needs. Any unused space is divided
- * evenly between cells for which @expand is %TRUE.
- **/
-void
-pspp_sheet_view_column_pack_start (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell,
- gboolean expand)
-{
- gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (tree_column), cell, expand);
-}
-
-/**
- * pspp_sheet_view_column_pack_end:
- * @tree_column: A #PsppSheetViewColumn.
- * @cell: The #GtkCellRenderer.
- * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
- *
- * Adds the @cell to end of the column. If @expand is %FALSE, then the @cell
- * is allocated no more space than it needs. Any unused space is divided
- * evenly between cells for which @expand is %TRUE.
- **/
-void
-pspp_sheet_view_column_pack_end (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell,
- gboolean expand)
-{
- gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (tree_column), cell, expand);
-}
-
-/**
- * pspp_sheet_view_column_clear:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Unsets all the mappings on all renderers on the @tree_column.
- **/
-void
-pspp_sheet_view_column_clear (PsppSheetViewColumn *tree_column)
-{
- gtk_cell_layout_clear (GTK_CELL_LAYOUT (tree_column));
-}
-
-static GList *
-pspp_sheet_view_column_cell_layout_get_cells (GtkCellLayout *layout)
-{
- PsppSheetViewColumn *tree_column = PSPP_SHEET_VIEW_COLUMN (layout);
- GList *retval = NULL, *list;
-
- g_return_val_if_fail (tree_column != NULL, NULL);
-
- for (list = tree_column->cell_list; list; list = list->next)
- {
- PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
-
- retval = g_list_append (retval, info->cell);
- }
-
- return retval;
-}
-
-/**
- * pspp_sheet_view_column_get_cell_renderers:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns a newly-allocated #GList of all the cell renderers in the column,
- * in no particular order. The list must be freed with g_list_free().
- *
- * Return value: A list of #GtkCellRenderers
- *
- * Deprecated: 2.18: use gtk_cell_layout_get_cells() instead.
- **/
-GList *
-pspp_sheet_view_column_get_cell_renderers (PsppSheetViewColumn *tree_column)
-{
- return pspp_sheet_view_column_cell_layout_get_cells (GTK_CELL_LAYOUT (tree_column));
-}
-
-/**
- * pspp_sheet_view_column_add_attribute:
- * @tree_column: A #PsppSheetViewColumn.
- * @cell_renderer: the #GtkCellRenderer to set attributes on
- * @attribute: An attribute on the renderer
- * @column: The column position on the model to get the attribute from.
- *
- * Adds an attribute mapping to the list in @tree_column. The @column is the
- * column of the model to get a value from, and the @attribute is the
- * parameter on @cell_renderer to be set from the value. So for example
- * if column 2 of the model contains strings, you could have the
- * "text" attribute of a #GtkCellRendererText get its values from
- * column 2.
- **/
-void
-pspp_sheet_view_column_add_attribute (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell_renderer,
- const gchar *attribute,
- gint column)
-{
- gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (tree_column),
- cell_renderer, attribute, column);
-}
-
-static void
-pspp_sheet_view_column_set_attributesv (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell_renderer,
- va_list args)
-{
- gchar *attribute;
- gint column;
-
- attribute = va_arg (args, gchar *);
-
- pspp_sheet_view_column_clear_attributes (tree_column, cell_renderer);
-
- while (attribute != NULL)
- {
- column = va_arg (args, gint);
- pspp_sheet_view_column_add_attribute (tree_column, cell_renderer, attribute, column);
- attribute = va_arg (args, gchar *);
- }
-}
-
-/**
- * pspp_sheet_view_column_set_attributes:
- * @tree_column: A #PsppSheetViewColumn.
- * @cell_renderer: the #GtkCellRenderer we're setting the attributes of
- * @Varargs: A %NULL-terminated list of attributes.
- *
- * Sets the attributes in the list as the attributes of @tree_column.
- * The attributes should be in attribute/column order, as in
- * pspp_sheet_view_column_add_attribute(). All existing attributes
- * are removed, and replaced with the new attributes.
- **/
-void
-pspp_sheet_view_column_set_attributes (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell_renderer,
- ...)
-{
- va_list args;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
- g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
- g_return_if_fail (pspp_sheet_view_column_get_cell_info (tree_column, cell_renderer));
-
- va_start (args, cell_renderer);
- pspp_sheet_view_column_set_attributesv (tree_column, cell_renderer, args);
- va_end (args);
-}
-
-
-/**
- * pspp_sheet_view_column_set_cell_data_func:
- * @tree_column: A #PsppSheetViewColumn
- * @cell_renderer: A #GtkCellRenderer
- * @func: The #PsppSheetViewColumnFunc to use.
- * @func_data: The user data for @func.
- * @destroy: The destroy notification for @func_data
- *
- * Sets the #PsppSheetViewColumnFunc to use for the column. This
- * function is used instead of the standard attributes mapping for
- * setting the column value, and should set the value of @tree_column's
- * cell renderer as appropriate. @func may be %NULL to remove an
- * older one.
- **/
-void
-pspp_sheet_view_column_set_cell_data_func (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell_renderer,
- PsppSheetCellDataFunc func,
- gpointer func_data,
- GDestroyNotify destroy)
-{
- gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (tree_column),
- cell_renderer,
- (GtkCellLayoutDataFunc)func,
- func_data, destroy);
-}
-
-
-/**
- * pspp_sheet_view_column_clear_attributes:
- * @tree_column: a #PsppSheetViewColumn
- * @cell_renderer: a #GtkCellRenderer to clear the attribute mapping on.
- *
- * Clears all existing attributes previously set with
- * pspp_sheet_view_column_set_attributes().
- **/
-void
-pspp_sheet_view_column_clear_attributes (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell_renderer)
-{
- gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (tree_column),
- cell_renderer);
-}
-
-/**
- * pspp_sheet_view_column_set_spacing:
- * @tree_column: A #PsppSheetViewColumn.
- * @spacing: distance between cell renderers in pixels.
- *
- * Sets the spacing field of @tree_column, which is the number of pixels to
- * place between cell renderers packed into it.
- **/
-void
-pspp_sheet_view_column_set_spacing (PsppSheetViewColumn *tree_column,
- gint spacing)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
- g_return_if_fail (spacing >= 0);
-
- if (tree_column->spacing == spacing)
- return;
-
- tree_column->spacing = spacing;
- if (tree_column->tree_view)
- _pspp_sheet_view_column_cell_set_dirty (tree_column);
-}
-
-/**
- * pspp_sheet_view_column_get_spacing:
- * @tree_column: A #PsppSheetViewColumn.
- *
- * Returns the spacing of @tree_column.
- *
- * Return value: the spacing of @tree_column.
- **/
-gint
-pspp_sheet_view_column_get_spacing (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
-
- return tree_column->spacing;
-}
-
-/* Options for manipulating the columns */
-
-/**
- * pspp_sheet_view_column_set_visible:
- * @tree_column: A #PsppSheetViewColumn.
- * @visible: %TRUE if the @tree_column is visible.
- *
- * Sets the visibility of @tree_column.
- **/
-void
-pspp_sheet_view_column_set_visible (PsppSheetViewColumn *tree_column,
- gboolean visible)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
- visible = !! visible;
-
- if (tree_column->visible == visible)
- return;
-
- tree_column->visible = visible;
-
- if (tree_column->visible)
- _pspp_sheet_view_column_cell_set_dirty (tree_column);
-
- pspp_sheet_view_column_update_button (tree_column);
- g_object_notify (G_OBJECT (tree_column), "visible");
-}
-
-/**
- * pspp_sheet_view_column_get_visible:
- * @tree_column: A #PsppSheetViewColumn.
- *
- * Returns %TRUE if @tree_column is visible.
- *
- * Return value: whether the column is visible or not. If it is visible, then
- * the tree will show the column.
- **/
-gboolean
-pspp_sheet_view_column_get_visible (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
- return tree_column->visible;
-}
-
-/**
- * pspp_sheet_view_column_set_resizable:
- * @tree_column: A #PsppSheetViewColumn
- * @resizable: %TRUE, if the column can be resized
- *
- * If @resizable is %TRUE, then the user can explicitly resize the column by
- * grabbing the outer edge of the column button.
- **/
-void
-pspp_sheet_view_column_set_resizable (PsppSheetViewColumn *tree_column,
- gboolean resizable)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
- resizable = !! resizable;
-
- if (tree_column->resizable == resizable)
- return;
-
- tree_column->resizable = resizable;
-
- pspp_sheet_view_column_update_button (tree_column);
-
- g_object_notify (G_OBJECT (tree_column), "resizable");
-}
-
-/**
- * pspp_sheet_view_column_get_resizable:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns %TRUE if the @tree_column can be resized by the end user.
- *
- * Return value: %TRUE, if the @tree_column can be resized.
- **/
-gboolean
-pspp_sheet_view_column_get_resizable (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
- return tree_column->resizable;
-}
-
-
-/**
- * pspp_sheet_view_column_get_width:
- * @tree_column: A #PsppSheetViewColumn.
- *
- * Returns the current size of @tree_column in pixels.
- *
- * Return value: The current width of @tree_column.
- **/
-gint
-pspp_sheet_view_column_get_width (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
-
- return tree_column->width;
-}
-
-/**
- * pspp_sheet_view_column_set_fixed_width:
- * @tree_column: A #PsppSheetViewColumn.
- * @fixed_width: The size to set @tree_column to. Must be greater than 0.
- *
- * Sets the size of the column in pixels. The size of the column is clamped to
- * the min/max width for the column. Please note that the min/max width of the
- * column doesn't actually affect the "fixed_width" property of the widget, just
- * the actual size when displayed.
- **/
-void
-pspp_sheet_view_column_set_fixed_width (PsppSheetViewColumn *tree_column,
- gint fixed_width)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
- g_return_if_fail (fixed_width > 0);
-
- tree_column->fixed_width = fixed_width;
- tree_column->use_resized_width = FALSE;
-
- if (tree_column->tree_view &&
- gtk_widget_get_realized (tree_column->tree_view))
- {
- gtk_widget_queue_resize (tree_column->tree_view);
- }
-
- g_object_notify (G_OBJECT (tree_column), "fixed-width");
-}
-
-/**
- * pspp_sheet_view_column_get_fixed_width:
- * @tree_column: a #PsppSheetViewColumn
- *
- * Gets the fixed width of the column. This value is only meaning may not be
- * the actual width of the column on the screen, just what is requested.
- *
- * Return value: the fixed width of the column
- **/
-gint
-pspp_sheet_view_column_get_fixed_width (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
-
- return tree_column->fixed_width;
-}
-
-/**
- * pspp_sheet_view_column_set_min_width:
- * @tree_column: A #PsppSheetViewColumn.
- * @min_width: The minimum width of the column in pixels, or -1.
- *
- * Sets the minimum width of the @tree_column. If @min_width is -1, then the
- * minimum width is unset.
- **/
-void
-pspp_sheet_view_column_set_min_width (PsppSheetViewColumn *tree_column,
- gint min_width)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
- g_return_if_fail (min_width >= -1);
-
- if (min_width == tree_column->min_width)
- return;
-
- if (tree_column->visible &&
- tree_column->tree_view != NULL &&
- gtk_widget_get_realized (tree_column->tree_view))
- {
- if (min_width > tree_column->width)
- gtk_widget_queue_resize (tree_column->tree_view);
- }
-
- tree_column->min_width = min_width;
- g_object_freeze_notify (G_OBJECT (tree_column));
- if (tree_column->max_width != -1 && tree_column->max_width < min_width)
- {
- tree_column->max_width = min_width;
- g_object_notify (G_OBJECT (tree_column), "max-width");
- }
- g_object_notify (G_OBJECT (tree_column), "min-width");
- g_object_thaw_notify (G_OBJECT (tree_column));
-}
-
-/**
- * pspp_sheet_view_column_get_min_width:
- * @tree_column: A #PsppSheetViewColumn.
- *
- * Returns the minimum width in pixels of the @tree_column, or -1 if no minimum
- * width is set.
- *
- * Return value: The minimum width of the @tree_column.
- **/
-gint
-pspp_sheet_view_column_get_min_width (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
-
- return tree_column->min_width;
-}
-
-/**
- * pspp_sheet_view_column_set_max_width:
- * @tree_column: A #PsppSheetViewColumn.
- * @max_width: The maximum width of the column in pixels, or -1.
- *
- * Sets the maximum width of the @tree_column. If @max_width is -1, then the
- * maximum width is unset. Note, the column can actually be wider than max
- * width if it's the last column in a view. In this case, the column expands to
- * fill any extra space.
- **/
-void
-pspp_sheet_view_column_set_max_width (PsppSheetViewColumn *tree_column,
- gint max_width)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
- g_return_if_fail (max_width >= -1);
-
- if (max_width == tree_column->max_width)
- return;
-
- if (tree_column->visible &&
- tree_column->tree_view != NULL &&
- gtk_widget_get_realized (tree_column->tree_view))
- {
- if (max_width != -1 && max_width < tree_column->width)
- gtk_widget_queue_resize (tree_column->tree_view);
- }
-
- tree_column->max_width = max_width;
- g_object_freeze_notify (G_OBJECT (tree_column));
- if (max_width != -1 && max_width < tree_column->min_width)
- {
- tree_column->min_width = max_width;
- g_object_notify (G_OBJECT (tree_column), "min-width");
- }
- g_object_notify (G_OBJECT (tree_column), "max-width");
- g_object_thaw_notify (G_OBJECT (tree_column));
-}
-
-/**
- * pspp_sheet_view_column_get_max_width:
- * @tree_column: A #PsppSheetViewColumn.
- *
- * Returns the maximum width in pixels of the @tree_column, or -1 if no maximum
- * width is set.
- *
- * Return value: The maximum width of the @tree_column.
- **/
-gint
-pspp_sheet_view_column_get_max_width (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), -1);
-
- return tree_column->max_width;
-}
-
-/**
- * pspp_sheet_view_column_clicked:
- * @tree_column: a #PsppSheetViewColumn
- *
- * Emits the "clicked" signal on the column. This function will only work if
- * @tree_column is clickable.
- **/
-void
-pspp_sheet_view_column_clicked (PsppSheetViewColumn *tree_column)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
- if (tree_column->visible &&
- tree_column->button &&
- tree_column->clickable)
- gtk_button_clicked (GTK_BUTTON (tree_column->button));
-}
-
-/**
- * pspp_sheet_view_column_set_title:
- * @tree_column: A #PsppSheetViewColumn.
- * @title: The title of the @tree_column.
- *
- * Sets the title of the @tree_column. If a custom widget has been set, then
- * this value is ignored.
- **/
-void
-pspp_sheet_view_column_set_title (PsppSheetViewColumn *tree_column,
- const gchar *title)
-{
- gchar *new_title;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
- new_title = g_strdup (title);
- g_free (tree_column->title);
- tree_column->title = new_title;
-
- pspp_sheet_view_column_update_button (tree_column);
- g_object_notify (G_OBJECT (tree_column), "title");
-}
-
-/**
- * pspp_sheet_view_column_get_title:
- * @tree_column: A #PsppSheetViewColumn.
- *
- * Returns the title of the widget.
- *
- * Return value: the title of the column. This string should not be
- * modified or freed.
- **/
-const gchar *
-pspp_sheet_view_column_get_title (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
-
- return tree_column->title;
-}
-
-/**
- * pspp_sheet_view_column_set_expand:
- * @tree_column: A #PsppSheetViewColumn
- * @expand: %TRUE if the column should take available extra space, %FALSE if not
- *
- * Sets the column to take available extra space. This space is shared equally
- * amongst all columns that have the expand set to %TRUE. If no column has this
- * option set, then the last column gets all extra space. By default, every
- * column is created with this %FALSE.
- *
- * Since: 2.4
- **/
-void
-pspp_sheet_view_column_set_expand (PsppSheetViewColumn *tree_column,
- gboolean expand)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
- expand = !!expand;
- if (tree_column->expand == expand)
- return;
- tree_column->expand = expand;
-
- if (tree_column->visible &&
- tree_column->tree_view != NULL &&
- gtk_widget_get_realized (tree_column->tree_view))
- {
- /* We want to continue using the original width of the
- * column that includes additional space added by the user
- * resizing the columns and possibly extra (expanded) space, which
- * are not included in the resized width.
- */
- tree_column->use_resized_width = FALSE;
-
- gtk_widget_queue_resize (tree_column->tree_view);
- }
-
- g_object_notify (G_OBJECT (tree_column), "expand");
-}
-
-/**
- * pspp_sheet_view_column_get_expand:
- * @tree_column: a #PsppSheetViewColumn
- *
- * Return %TRUE if the column expands to take any available space.
- *
- * Return value: %TRUE, if the column expands
- *
- * Since: 2.4
- **/
-gboolean
-pspp_sheet_view_column_get_expand (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
- return tree_column->expand;
-}
-
-/**
- * pspp_sheet_view_column_set_clickable:
- * @tree_column: A #PsppSheetViewColumn.
- * @clickable: %TRUE if the header is active.
- *
- * Sets the header to be active if @active is %TRUE. When the header is active,
- * then it can take keyboard focus, and can be clicked.
- **/
-void
-pspp_sheet_view_column_set_clickable (PsppSheetViewColumn *tree_column,
- gboolean clickable)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
- clickable = !! clickable;
- if (tree_column->clickable == clickable)
- return;
-
- tree_column->clickable = clickable;
- pspp_sheet_view_column_update_button (tree_column);
- g_object_notify (G_OBJECT (tree_column), "clickable");
-}
-
-/**
- * pspp_sheet_view_column_get_clickable:
- * @tree_column: a #PsppSheetViewColumn
- *
- * Returns %TRUE if the user can click on the header for the column.
- *
- * Return value: %TRUE if user can click the column header.
- **/
-gboolean
-pspp_sheet_view_column_get_clickable (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
- return tree_column->clickable;
-}
-
-/**
- * pspp_sheet_view_column_set_widget:
- * @tree_column: A #PsppSheetViewColumn.
- * @widget: (allow-none): A child #GtkWidget, or %NULL.
- *
- * Sets the widget in the header to be @widget. If widget is %NULL, then the
- * header button is set with a #GtkLabel set to the title of @tree_column.
- **/
-void
-pspp_sheet_view_column_set_widget (PsppSheetViewColumn *tree_column,
- GtkWidget *widget)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
- g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
-
- if (widget)
- g_object_ref_sink (widget);
-
- if (tree_column->child)
- g_object_unref (tree_column->child);
-
- tree_column->child = widget;
- pspp_sheet_view_column_update_button (tree_column);
- g_object_notify (G_OBJECT (tree_column), "widget");
-}
-
-/**
- * pspp_sheet_view_column_get_widget:
- * @tree_column: A #PsppSheetViewColumn.
- *
- * Returns the #GtkWidget in the button on the column header. If a custom
- * widget has not been set then %NULL is returned.
- *
- * Return value: The #GtkWidget in the column header, or %NULL
- **/
-GtkWidget *
-pspp_sheet_view_column_get_widget (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
-
- return tree_column->child;
-}
-
-/**
- * pspp_sheet_view_column_set_alignment:
- * @tree_column: A #PsppSheetViewColumn.
- * @xalign: The alignment, which is between [0.0 and 1.0] inclusive.
- *
- * Sets the alignment of the title or custom widget inside the column header.
- * The alignment determines its location inside the button.
- **/
-void
-pspp_sheet_view_column_set_alignment (PsppSheetViewColumn *tree_column,
- GtkAlign xalign)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
-
- if (tree_column->halign == xalign)
- return;
-
- tree_column->halign = xalign;
- pspp_sheet_view_column_update_button (tree_column);
- g_object_notify (G_OBJECT (tree_column), "alignment");
-}
-
-/**
- * pspp_sheet_view_column_get_alignment:
- * @tree_column: A #PsppSheetViewColumn.
- *
- * Returns the current x alignment of @tree_column.
- *
- * Return value: The current alignent of @tree_column.
- **/
-GtkAlign
-pspp_sheet_view_column_get_alignment (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), GTK_ALIGN_CENTER);
-
- return tree_column->halign;
-}
-
-
-/**
- * pspp_sheet_view_column_set_reorderable:
- * @tree_column: A #PsppSheetViewColumn
- * @reorderable: %TRUE, if the column can be reordered.
- *
- * If @reorderable is %TRUE, then the column can be reordered by the end user
- * dragging the header.
- **/
-void
-pspp_sheet_view_column_set_reorderable (PsppSheetViewColumn *tree_column,
- gboolean reorderable)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
- /* if (reorderable)
- pspp_sheet_view_column_set_clickable (tree_column, TRUE);*/
-
- reorderable = !!reorderable;
- if (tree_column->reorderable == reorderable)
- return;
-
- tree_column->reorderable = reorderable;
- pspp_sheet_view_column_update_button (tree_column);
- g_object_notify (G_OBJECT (tree_column), "reorderable");
-}
-
-/**
- * pspp_sheet_view_column_get_reorderable:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns %TRUE if the @tree_column can be reordered by the user.
- *
- * Return value: %TRUE if the @tree_column can be reordered by the user.
- **/
-gboolean
-pspp_sheet_view_column_get_reorderable (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
- return tree_column->reorderable;
-}
-
-/**
- * pspp_sheet_view_column_set_quick_edit:
- * @tree_column: A #PsppSheetViewColumn
- * @quick_edit: If true, editing starts upon the first click in the column. If
- * false, the first click selects the column and a second click is needed to
- * begin editing. This has no effect on cells that are not editable.
- **/
-void
-pspp_sheet_view_column_set_quick_edit (PsppSheetViewColumn *tree_column,
- gboolean quick_edit)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
- quick_edit = !!quick_edit;
- if (tree_column->quick_edit != quick_edit)
- {
- tree_column->quick_edit = quick_edit;
- g_object_notify (G_OBJECT (tree_column), "quick-edit");
- }
-}
-
-/**
- * pspp_sheet_view_column_get_quick_edit:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns %TRUE if editing starts upon the first click in the column. Returns
- * %FALSE, the first click selects the column and a second click is needed to
- * begin editing. This is not meaningful for cells that are not editable.
- *
- * Return value: %TRUE if editing starts upon the first click.
- **/
-gboolean
-pspp_sheet_view_column_get_quick_edit (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
- return tree_column->quick_edit;
-}
-
-
-/**
- * pspp_sheet_view_column_set_selected:
- * @tree_column: A #PsppSheetViewColumn
- * @selected: If true, the column is selected as part of a rectangular
- * selection.
- **/
-void
-pspp_sheet_view_column_set_selected (PsppSheetViewColumn *tree_column,
- gboolean selected)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
- selected = !!selected;
- if (tree_column->selected != selected)
- {
- PsppSheetSelection *selection;
- PsppSheetView *sheet_view;
-
- if (tree_column->tree_view != NULL)
- gtk_widget_queue_draw (GTK_WIDGET (tree_column->tree_view));
- tree_column->selected = selected;
- g_object_notify (G_OBJECT (tree_column), "selected");
-
- sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (
- tree_column));
- selection = pspp_sheet_view_get_selection (sheet_view);
- _pspp_sheet_selection_emit_changed (selection);
- }
-}
-
-/**
- * pspp_sheet_view_column_get_selected:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns %TRUE if the column is selected as part of a rectangular
- * selection.
- *
- * Return value: %TRUE if the column is selected as part of a rectangular
- * selection.
- **/
-gboolean
-pspp_sheet_view_column_get_selected (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
- return tree_column->selected;
-}
-
-/**
- * pspp_sheet_view_column_set_selectable:
- * @tree_column: A #PsppSheetViewColumn
- * @selectable: If true, the column may be selected as part of a rectangular
- * selection.
- **/
-void
-pspp_sheet_view_column_set_selectable (PsppSheetViewColumn *tree_column,
- gboolean selectable)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
- selectable = !!selectable;
- if (tree_column->selectable != selectable)
- {
- if (tree_column->tree_view != NULL)
- gtk_widget_queue_draw (GTK_WIDGET (tree_column->tree_view));
- tree_column->selectable = selectable;
- g_object_notify (G_OBJECT (tree_column), "selectable");
- }
-}
-
-/**
- * pspp_sheet_view_column_get_selectable:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns %TRUE if the column may be selected as part of a rectangular
- * selection.
- *
- * Return value: %TRUE if the column may be selected as part of a rectangular
- * selection.
- **/
-gboolean
-pspp_sheet_view_column_get_selectable (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
- return tree_column->selectable;
-}
-
-
-/**
- * pspp_sheet_view_column_set_row_head:
- * @tree_column: A #PsppSheetViewColumn
- * @row_head: If true, the column is a "row head", analogous to a column head.
- * See the description of the row-head property for more information.
- **/
-void
-pspp_sheet_view_column_set_row_head (PsppSheetViewColumn *tree_column,
- gboolean row_head)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
- row_head = !!row_head;
- if (tree_column->row_head != row_head)
- {
- tree_column->row_head = row_head;
- g_object_notify (G_OBJECT (tree_column), "row_head");
- }
-}
-
-/**
- * pspp_sheet_view_column_get_row_head:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns %TRUE if the column is a row head.
- *
- * Return value: %TRUE if the column is a row head.
- **/
-gboolean
-pspp_sheet_view_column_get_row_head (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
- return tree_column->row_head;
-}
-
-
-/**
- * pspp_sheet_view_column_set_tabbable:
- * @tree_column: A #PsppSheetViewColumn
- * @tabbable: If true, the column is "tabbable", meaning that Tab and Shift+Tab
- * in the sheet visit this column. If false, Tab and Shift+Tab skip this
- * column.
- **/
-void
-pspp_sheet_view_column_set_tabbable (PsppSheetViewColumn *tree_column,
- gboolean tabbable)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
- tabbable = !!tabbable;
- if (tree_column->tabbable != tabbable)
- {
- tree_column->tabbable = tabbable;
- g_object_notify (G_OBJECT (tree_column), "tabbable");
- }
-}
-
-/**
- * pspp_sheet_view_column_get_tabbable:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns %TRUE if the column is tabbable.
- *
- * Return value: %TRUE if the column is tabbable.
- **/
-gboolean
-pspp_sheet_view_column_get_tabbable (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
- return tree_column->tabbable;
-}
-
-
-/**
- * pspp_sheet_view_column_set_sort_column_id:
- * @tree_column: a #PsppSheetViewColumn
- * @sort_column_id: The @sort_column_id of the model to sort on.
- *
- * Sets the logical @sort_column_id that this column sorts on when this column
- * is selected for sorting. Doing so makes the column header clickable.
- **/
-void
-pspp_sheet_view_column_set_sort_column_id (PsppSheetViewColumn *tree_column,
- gint sort_column_id)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
- g_return_if_fail (sort_column_id >= -1);
-
- if (tree_column->sort_column_id == sort_column_id)
- return;
-
- tree_column->sort_column_id = sort_column_id;
-
- /* Handle unsetting the id */
- if (sort_column_id == -1)
- {
- GtkTreeModel *model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (tree_column->tree_view));
-
- if (tree_column->sort_clicked_signal)
- {
- g_signal_handler_disconnect (tree_column, tree_column->sort_clicked_signal);
- tree_column->sort_clicked_signal = 0;
- }
-
- if (tree_column->sort_column_changed_signal)
- {
- g_signal_handler_disconnect (model, tree_column->sort_column_changed_signal);
- tree_column->sort_column_changed_signal = 0;
- }
-
- pspp_sheet_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING);
- pspp_sheet_view_column_set_sort_indicator (tree_column, FALSE);
- pspp_sheet_view_column_set_clickable (tree_column, FALSE);
- g_object_notify (G_OBJECT (tree_column), "sort-column-id");
- return;
- }
-
- pspp_sheet_view_column_set_clickable (tree_column, TRUE);
-
- if (! tree_column->sort_clicked_signal)
- tree_column->sort_clicked_signal = g_signal_connect (tree_column,
- "clicked",
- G_CALLBACK (pspp_sheet_view_column_sort),
- NULL);
-
- pspp_sheet_view_column_setup_sort_column_id_callback (tree_column);
- g_object_notify (G_OBJECT (tree_column), "sort-column-id");
-}
-
-/**
- * pspp_sheet_view_column_get_sort_column_id:
- * @tree_column: a #PsppSheetViewColumn
- *
- * Gets the logical @sort_column_id that the model sorts on when this
- * column is selected for sorting.
- * See pspp_sheet_view_column_set_sort_column_id().
- *
- * Return value: the current @sort_column_id for this column, or -1 if
- * this column can't be used for sorting.
- **/
-gint
-pspp_sheet_view_column_get_sort_column_id (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
-
- return tree_column->sort_column_id;
-}
-
-/**
- * pspp_sheet_view_column_set_sort_indicator:
- * @tree_column: a #PsppSheetViewColumn
- * @setting: %TRUE to display an indicator that the column is sorted
- *
- * Call this function with a @setting of %TRUE to display an arrow in
- * the header button indicating the column is sorted. Call
- * pspp_sheet_view_column_set_sort_order() to change the direction of
- * the arrow.
- *
- **/
-void
-pspp_sheet_view_column_set_sort_indicator (PsppSheetViewColumn *tree_column,
- gboolean setting)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
- setting = setting != FALSE;
-
- if (setting == tree_column->show_sort_indicator)
- return;
-
- tree_column->show_sort_indicator = setting;
- pspp_sheet_view_column_update_button (tree_column);
- g_object_notify (G_OBJECT (tree_column), "sort-indicator");
-}
-
-/**
- * pspp_sheet_view_column_get_sort_indicator:
- * @tree_column: a #PsppSheetViewColumn
- *
- * Gets the value set by pspp_sheet_view_column_set_sort_indicator().
- *
- * Return value: whether the sort indicator arrow is displayed
- **/
-gboolean
-pspp_sheet_view_column_get_sort_indicator (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
- return tree_column->show_sort_indicator;
-}
-
-/**
- * pspp_sheet_view_column_set_sort_order:
- * @tree_column: a #PsppSheetViewColumn
- * @order: sort order that the sort indicator should indicate
- *
- * Changes the appearance of the sort indicator.
- *
- * This <emphasis>does not</emphasis> actually sort the model. Use
- * pspp_sheet_view_column_set_sort_column_id() if you want automatic sorting
- * support. This function is primarily for custom sorting behavior, and should
- * be used in conjunction with gtk_tree_sortable_set_sort_column() to do
- * that. For custom models, the mechanism will vary.
- *
- * The sort indicator changes direction to indicate normal sort or reverse sort.
- * Note that you must have the sort indicator enabled to see anything when
- * calling this function; see pspp_sheet_view_column_set_sort_indicator().
- **/
-void
-pspp_sheet_view_column_set_sort_order (PsppSheetViewColumn *tree_column,
- GtkSortType order)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
- if (order == tree_column->sort_order)
- return;
-
- tree_column->sort_order = order;
- pspp_sheet_view_column_update_button (tree_column);
- g_object_notify (G_OBJECT (tree_column), "sort-order");
-}
-
-/**
- * pspp_sheet_view_column_get_sort_order:
- * @tree_column: a #PsppSheetViewColumn
- *
- * Gets the value set by pspp_sheet_view_column_set_sort_order().
- *
- * Return value: the sort order the sort indicator is indicating
- **/
-GtkSortType
-pspp_sheet_view_column_get_sort_order (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), 0);
-
- return tree_column->sort_order;
-}
-
-/**
- * pspp_sheet_view_column_cell_set_cell_data:
- * @tree_column: A #PsppSheetViewColumn.
- * @tree_model: The #GtkTreeModel to to get the cell renderers attributes from.
- * @iter: The #GtkTreeIter to to get the cell renderer's attributes from.
- *
- * Sets the cell renderer based on the @tree_model and @iter. That is, for
- * every attribute mapping in @tree_column, it will get a value from the set
- * column on the @iter, and use that value to set the attribute on the cell
- * renderer. This is used primarily by the #PsppSheetView.
- **/
-void
-pspp_sheet_view_column_cell_set_cell_data (PsppSheetViewColumn *tree_column,
- GtkTreeModel *tree_model,
- GtkTreeIter *iter)
-{
- GSList *list;
- GValue value = { 0, };
- GList *cell_list;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
- if (tree_model == NULL)
- return;
-
- for (cell_list = tree_column->cell_list; cell_list; cell_list = cell_list->next)
- {
- PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) cell_list->data;
- GObject *cell = (GObject *) info->cell;
-
- list = info->attributes;
-
- g_object_freeze_notify (cell);
-
- while (list && list->next)
- {
- gtk_tree_model_get_value (tree_model, iter,
- GPOINTER_TO_INT (list->next->data),
- &value);
- g_object_set_property (cell, (gchar *) list->data, &value);
- g_value_unset (&value);
- list = list->next->next;
- }
-
- if (info->func)
- (* info->func) (tree_column, info->cell, tree_model, iter, info->func_data);
- g_object_thaw_notify (G_OBJECT (info->cell));
- }
-
-}
-
-/**
- * pspp_sheet_view_column_cell_get_size:
- * @tree_column: A #PsppSheetViewColumn.
- * @cell_area: (allow-none): The area a cell in the column will be allocated, or %NULL
- * @x_offset: (allow-none): location to return x offset of a cell relative to @cell_area, or %NULL
- * @y_offset: (allow-none): location to return y offset of a cell relative to @cell_area, or %NULL
- * @width: (allow-none): location to return width needed to render a cell, or %NULL
- * @height: (allow-none): location to return height needed to render a cell, or %NULL
- *
- * Obtains the width and height needed to render the column. This is used
- * primarily by the #PsppSheetView.
- **/
-void
-pspp_sheet_view_column_cell_get_size (PsppSheetViewColumn *tree_column,
- const GdkRectangle *cell_area,
- gint *x_offset,
- gint *y_offset,
- gint *width,
- gint *height)
-{
- GList *list;
- gboolean first_cell = TRUE;
- gint focus_line_width;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
- if (height)
- * height = 0;
- if (width)
- * width = 0;
-
- gtk_widget_style_get (tree_column->tree_view, "focus-line-width", &focus_line_width, NULL);
-
- for (list = tree_column->cell_list; list; list = list->next)
- {
- PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
- gboolean visible;
- gint new_height = 0;
- gint new_width = 0;
- g_object_get (info->cell, "visible", &visible, NULL);
-
- if (visible == FALSE)
- continue;
-
- if (first_cell == FALSE && width)
- *width += tree_column->spacing;
-
- gtk_cell_renderer_get_padding (info->cell, x_offset, y_offset);
- gtk_cell_renderer_get_preferred_width (info->cell, tree_column->tree_view,
- NULL, &new_width);
-
- gtk_cell_renderer_get_preferred_height (info->cell, tree_column->tree_view,
- NULL, &new_height);
-
-
- if (height)
- * height = MAX (*height, new_height + focus_line_width * 2);
- info->requested_width = MAX (info->requested_width, new_width + focus_line_width * 2);
- if (width)
- * width += info->requested_width;
- first_cell = FALSE;
- }
-}
-
-/* rendering, event handling and rendering focus are somewhat complicated, and
- * quite a bit of code. Rather than duplicate them, we put them together to
- * keep the code in one place.
- *
- * To better understand what's going on, check out
- * docs/tree-column-sizing.png
- */
-enum {
- CELL_ACTION_RENDER,
- CELL_ACTION_FOCUS,
- CELL_ACTION_EVENT
-};
-
-static gboolean
-pspp_sheet_view_column_cell_process_action (PsppSheetViewColumn *tree_column,
- cairo_t *cr,
- const GdkRectangle *background_area,
- const GdkRectangle *cell_area,
- guint flags,
- gint action,
- GdkRectangle *focus_rectangle, /* FOCUS */
- GtkCellEditable **editable_widget, /* EVENT */
- GdkEvent *event, /* EVENT */
- gchar *path_string) /* EVENT */
-{
- GList *list;
- GdkRectangle real_cell_area;
- GdkRectangle real_background_area;
- gint depth = 0;
- gint expand_cell_count = 0;
- gint full_requested_width = 0;
- gint extra_space;
- gint min_x, min_y, max_x, max_y;
- gint focus_line_width;
- gint special_cells;
- gint horizontal_separator;
- gboolean cursor_row = FALSE;
- gboolean first_cell = TRUE;
- gboolean rtl;
- /* If we have rtl text, we need to transform our areas */
- GdkRectangle rtl_cell_area;
- GdkRectangle rtl_background_area;
-
- min_x = G_MAXINT;
- min_y = G_MAXINT;
- max_x = 0;
- max_y = 0;
-
- rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL);
- special_cells = _pspp_sheet_view_column_count_special_cells (tree_column);
-
- if (special_cells > 1 && action == CELL_ACTION_FOCUS)
- {
- PsppSheetViewColumnCellInfo *info = NULL;
- gboolean found_has_focus = FALSE;
-
- /* one should have focus */
- for (list = tree_column->cell_list; list; list = list->next)
- {
- info = list->data;
- if (info && info->has_focus)
- {
- found_has_focus = TRUE;
- break;
- }
- }
-
- if (!found_has_focus)
- {
- /* give the first one focus */
- info = pspp_sheet_view_column_cell_first (tree_column)->data;
- info->has_focus = TRUE;
- }
- }
-
- cursor_row = flags & GTK_CELL_RENDERER_FOCUSED;
-
- gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
- "focus-line-width", &focus_line_width,
- "horizontal-separator", &horizontal_separator,
- NULL);
-
- real_cell_area = *cell_area;
- real_background_area = *background_area;
-
-
- real_cell_area.x += focus_line_width;
- real_cell_area.y += focus_line_width;
- real_cell_area.height -= 2 * focus_line_width;
-
- if (rtl)
- depth = real_background_area.width - real_cell_area.width;
- else
- depth = real_cell_area.x - real_background_area.x;
-
- /* Find out how much extra space we have to allocate */
- for (list = tree_column->cell_list; list; list = list->next)
- {
- PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *)list->data;
-
- if (! gtk_cell_renderer_get_visible (info->cell))
- continue;
-
- if (info->expand == TRUE)
- expand_cell_count ++;
- full_requested_width += info->requested_width;
-
- if (!first_cell)
- full_requested_width += tree_column->spacing;
-
- first_cell = FALSE;
- }
-
- extra_space = cell_area->width - full_requested_width;
- if (extra_space < 0)
- extra_space = 0;
- else if (extra_space > 0 && expand_cell_count > 0)
- extra_space /= expand_cell_count;
-
- /* iterate list for GTK_PACK_START cells */
- for (list = tree_column->cell_list; list; list = list->next)
- {
- PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
-
- if (info->pack == GTK_PACK_END)
- continue;
-
- if (! gtk_cell_renderer_get_visible (info->cell))
- continue;
-
- if ((info->has_focus || special_cells == 1) && cursor_row)
- flags |= GTK_CELL_RENDERER_FOCUSED;
- else
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
-
- info->real_width = info->requested_width + (info->expand?extra_space:0);
-
- /* We constrain ourselves to only the width available */
- if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
- {
- info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
- }
-
- if (real_cell_area.x > cell_area->x + cell_area->width)
- break;
-
- real_cell_area.width = info->real_width;
- real_cell_area.width -= 2 * focus_line_width;
-
- if (list->next)
- {
- real_background_area.width = info->real_width + depth;
- }
- else
- {
- /* fill the rest of background for the last cell */
- real_background_area.width = background_area->x + background_area->width - real_background_area.x;
- }
-
- rtl_cell_area = real_cell_area;
- rtl_background_area = real_background_area;
-
- if (rtl)
- {
- rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
- rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
- }
-
- /* RENDER */
- if (action == CELL_ACTION_RENDER)
- {
- gtk_cell_renderer_render (info->cell,
- cr,
- tree_column->tree_view,
- &rtl_background_area,
- &rtl_cell_area,
- flags);
- }
- /* FOCUS */
- else if (action == CELL_ACTION_FOCUS)
- {
- gint x_offset, y_offset, width, height;
-
- gtk_cell_renderer_get_preferred_height (info->cell, tree_column->tree_view,
- NULL, &height);
-
- gtk_cell_renderer_get_preferred_width (info->cell, tree_column->tree_view,
- NULL, &width);
-
-
- gtk_cell_renderer_get_padding (info->cell,
- &x_offset, &y_offset);
-
- if (special_cells > 1)
- {
- if (info->has_focus)
- {
- min_x = rtl_cell_area.x + x_offset;
- max_x = min_x + width;
- min_y = rtl_cell_area.y + y_offset;
- max_y = min_y + height;
- }
- }
- else
- {
- if (min_x > (rtl_cell_area.x + x_offset))
- min_x = rtl_cell_area.x + x_offset;
- if (max_x < rtl_cell_area.x + x_offset + width)
- max_x = rtl_cell_area.x + x_offset + width;
- if (min_y > (rtl_cell_area.y + y_offset))
- min_y = rtl_cell_area.y + y_offset;
- if (max_y < rtl_cell_area.y + y_offset + height)
- max_y = rtl_cell_area.y + y_offset + height;
- }
- }
- /* EVENT */
- else if (action == CELL_ACTION_EVENT)
- {
- gboolean try_event = FALSE;
-
- if (event)
- {
- if (special_cells == 1)
- {
- /* only 1 activatable cell -> whole column can activate */
- if (cell_area->x <= ((GdkEventButton *)event)->x &&
- cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
- try_event = TRUE;
- }
- else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
- rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
- /* only activate cell if the user clicked on an individual
- * cell
- */
- try_event = TRUE;
- }
- else if (special_cells > 1 && info->has_focus)
- try_event = TRUE;
- else if (special_cells == 1)
- try_event = TRUE;
-
- if (try_event)
- {
- gboolean visible, mode;
-
- g_object_get (info->cell,
- "visible", &visible,
- "mode", &mode,
- NULL);
- if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
- {
- if (gtk_cell_renderer_activate (info->cell,
- event,
- tree_column->tree_view,
- path_string,
- &rtl_background_area,
- &rtl_cell_area,
- flags))
- {
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
- return TRUE;
- }
- }
- else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
- {
- *editable_widget =
- gtk_cell_renderer_start_editing (info->cell,
- event,
- tree_column->tree_view,
- path_string,
- &rtl_background_area,
- &rtl_cell_area,
- flags);
-
- if (*editable_widget != NULL)
- {
- g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
- info->in_editing_mode = TRUE;
- pspp_sheet_view_column_focus_cell (tree_column, info->cell);
-
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
-
- return TRUE;
- }
- }
- }
- }
-
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
-
- real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
- real_background_area.x += real_background_area.width + tree_column->spacing;
-
- /* Only needed for first cell */
- depth = 0;
- }
-
- /* iterate list for PACK_END cells */
- for (list = g_list_last (tree_column->cell_list); list; list = list->prev)
- {
- PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
-
- if (info->pack == GTK_PACK_START)
- continue;
-
- if (! gtk_cell_renderer_get_visible (info->cell))
- continue;
-
- if ((info->has_focus || special_cells == 1) && cursor_row)
- flags |= GTK_CELL_RENDERER_FOCUSED;
- else
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
-
- info->real_width = info->requested_width + (info->expand?extra_space:0);
-
- /* We constrain ourselves to only the width available */
- if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
- {
- info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
- }
-
- if (real_cell_area.x > cell_area->x + cell_area->width)
- break;
-
- real_cell_area.width = info->real_width;
- real_cell_area.width -= 2 * focus_line_width;
- real_background_area.width = info->real_width + depth;
-
- rtl_cell_area = real_cell_area;
- rtl_background_area = real_background_area;
- if (rtl)
- {
- rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
- rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
- }
-
- /* RENDER */
- if (action == CELL_ACTION_RENDER)
- {
- gtk_cell_renderer_render (info->cell,
- cr,
- tree_column->tree_view,
- &rtl_background_area,
- &rtl_cell_area,
- flags);
- }
- /* FOCUS */
- else if (action == CELL_ACTION_FOCUS)
- {
- gint x_offset, y_offset, width, height;
-
- gtk_cell_renderer_get_preferred_height (info->cell, tree_column->tree_view,
- NULL, &height);
-
- gtk_cell_renderer_get_preferred_width (info->cell, tree_column->tree_view,
- NULL, &width);
-
-
- gtk_cell_renderer_get_padding (info->cell,
- &x_offset, &y_offset);
-
- if (special_cells > 1)
- {
- if (info->has_focus)
- {
- min_x = rtl_cell_area.x + x_offset;
- max_x = min_x + width;
- min_y = rtl_cell_area.y + y_offset;
- max_y = min_y + height;
- }
- }
- else
- {
- if (min_x > (rtl_cell_area.x + x_offset))
- min_x = rtl_cell_area.x + x_offset;
- if (max_x < rtl_cell_area.x + x_offset + width)
- max_x = rtl_cell_area.x + x_offset + width;
- if (min_y > (rtl_cell_area.y + y_offset))
- min_y = rtl_cell_area.y + y_offset;
- if (max_y < rtl_cell_area.y + y_offset + height)
- max_y = rtl_cell_area.y + y_offset + height;
- }
- }
- /* EVENT */
- else if (action == CELL_ACTION_EVENT)
- {
- gboolean try_event = FALSE;
-
- if (event)
- {
- if (special_cells == 1)
- {
- /* only 1 activatable cell -> whole column can activate */
- if (cell_area->x <= ((GdkEventButton *)event)->x &&
- cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
- try_event = TRUE;
- }
- else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
- rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
- /* only activate cell if the user clicked on an individual
- * cell
- */
- try_event = TRUE;
- }
- else if (special_cells > 1 && info->has_focus)
- try_event = TRUE;
- else if (special_cells == 1)
- try_event = TRUE;
-
- if (try_event)
- {
- gboolean visible, mode;
-
- g_object_get (info->cell,
- "visible", &visible,
- "mode", &mode,
- NULL);
- if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
- {
- if (gtk_cell_renderer_activate (info->cell,
- event,
- tree_column->tree_view,
- path_string,
- &rtl_background_area,
- &rtl_cell_area,
- flags))
- {
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
- return TRUE;
- }
- }
- else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
- {
- *editable_widget =
- gtk_cell_renderer_start_editing (info->cell,
- event,
- tree_column->tree_view,
- path_string,
- &rtl_background_area,
- &rtl_cell_area,
- flags);
-
- if (*editable_widget != NULL)
- {
- g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
- info->in_editing_mode = TRUE;
- pspp_sheet_view_column_focus_cell (tree_column, info->cell);
-
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
- return TRUE;
- }
- }
- }
- }
-
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
-
- real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
- real_background_area.x += (real_background_area.width + tree_column->spacing);
-
- /* Only needed for first cell */
- depth = 0;
- }
-
- /* fill focus_rectangle when required */
- if (action == CELL_ACTION_FOCUS)
- {
- if (min_x >= max_x || min_y >= max_y)
- {
- *focus_rectangle = *cell_area;
- /* don't change the focus_rectangle, just draw it nicely inside
- * the cell area */
- }
- else
- {
- focus_rectangle->x = min_x - focus_line_width;
- focus_rectangle->y = min_y - focus_line_width;
- focus_rectangle->width = (max_x - min_x) + 2 * focus_line_width;
- focus_rectangle->height = (max_y - min_y) + 2 * focus_line_width;
- }
- }
-
- return FALSE;
-}
-
-/**
- * pspp_sheet_view_column_cell_render:
- * @tree_column: A #PsppSheetViewColumn.
- * @window: a #GdkDrawable to draw to
- * @background_area: entire cell area (including tree expanders and maybe padding on the sides)
- * @cell_area: area normally rendered by a cell renderer
- * @flags: flags that affect rendering
- *
- * Renders the cell contained by #tree_column. This is used primarily by the
- * #PsppSheetView.
- **/
-void
-_pspp_sheet_view_column_cell_render (PsppSheetViewColumn *tree_column,
- cairo_t *cr,
- const GdkRectangle *background_area,
- const GdkRectangle *cell_area,
- guint flags)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
- g_return_if_fail (background_area != NULL);
- g_return_if_fail (cell_area != NULL);
-
- pspp_sheet_view_column_cell_process_action (tree_column,
- cr,
- background_area,
- cell_area,
- flags,
- CELL_ACTION_RENDER,
- NULL, NULL, NULL, NULL);
-}
-
-gboolean
-_pspp_sheet_view_column_cell_event (PsppSheetViewColumn *tree_column,
- GtkCellEditable **editable_widget,
- GdkEvent *event,
- gchar *path_string,
- const GdkRectangle *background_area,
- const GdkRectangle *cell_area,
- guint flags)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
- return pspp_sheet_view_column_cell_process_action (tree_column,
- NULL,
- background_area,
- cell_area,
- flags,
- CELL_ACTION_EVENT,
- NULL,
- editable_widget,
- event,
- path_string);
-}
-
-void
-_pspp_sheet_view_column_get_focus_area (PsppSheetViewColumn *tree_column,
- const GdkRectangle *background_area,
- const GdkRectangle *cell_area,
- GdkRectangle *focus_area)
-{
- pspp_sheet_view_column_cell_process_action (tree_column,
- NULL,
- background_area,
- cell_area,
- 0,
- CELL_ACTION_FOCUS,
- focus_area,
- NULL, NULL, NULL);
-}
-
-
-/* cell list manipulation */
-static GList *
-pspp_sheet_view_column_cell_first (PsppSheetViewColumn *tree_column)
-{
- GList *list = tree_column->cell_list;
-
- /* first GTK_PACK_START cell we find */
- for ( ; list; list = list->next)
- {
- PsppSheetViewColumnCellInfo *info = list->data;
- if (info->pack == GTK_PACK_START)
- return list;
- }
-
- /* hmm, else the *last* GTK_PACK_END cell */
- list = g_list_last (tree_column->cell_list);
-
- for ( ; list; list = list->prev)
- {
- PsppSheetViewColumnCellInfo *info = list->data;
- if (info->pack == GTK_PACK_END)
- return list;
- }
-
- return NULL;
-}
-
-static GList *
-pspp_sheet_view_column_cell_last (PsppSheetViewColumn *tree_column)
-{
- GList *list = tree_column->cell_list;
-
- /* *first* GTK_PACK_END cell we find */
- for ( ; list ; list = list->next)
- {
- PsppSheetViewColumnCellInfo *info = list->data;
- if (info->pack == GTK_PACK_END)
- return list;
- }
-
- /* hmm, else the last GTK_PACK_START cell */
- list = g_list_last (tree_column->cell_list);
-
- for ( ; list; list = list->prev)
- {
- PsppSheetViewColumnCellInfo *info = list->data;
- if (info->pack == GTK_PACK_START)
- return list;
- }
-
- return NULL;
-}
-
-
-static GList *
-pspp_sheet_view_column_cell_next (PsppSheetViewColumn *tree_column,
- GList *current)
-{
- GList *list;
- PsppSheetViewColumnCellInfo *info = current->data;
-
- if (info->pack == GTK_PACK_START)
- {
- for (list = current->next; list; list = list->next)
- {
- PsppSheetViewColumnCellInfo *inf = list->data;
- if (inf->pack == GTK_PACK_START)
- return list;
- }
-
- /* out of GTK_PACK_START cells, get *last* GTK_PACK_END one */
- list = g_list_last (tree_column->cell_list);
- for (; list; list = list->prev)
- {
- PsppSheetViewColumnCellInfo *inf = list->data;
- if (inf->pack == GTK_PACK_END)
- return list;
- }
- }
-
- for (list = current->prev; list; list = list->prev)
- {
- PsppSheetViewColumnCellInfo *inf = list->data;
- if (inf->pack == GTK_PACK_END)
- return list;
- }
-
- return NULL;
-}
-
-static GList *
-pspp_sheet_view_column_cell_prev (PsppSheetViewColumn *tree_column,
- GList *current)
-{
- GList *list;
- PsppSheetViewColumnCellInfo *info = current->data;
-
- if (info->pack == GTK_PACK_END)
- {
- for (list = current->next; list; list = list->next)
- {
- PsppSheetViewColumnCellInfo *inf = list->data;
- if (inf->pack == GTK_PACK_END)
- return list;
- }
-
- /* out of GTK_PACK_END, get last GTK_PACK_START one */
- list = g_list_last (tree_column->cell_list);
- for ( ; list; list = list->prev)
- {
- PsppSheetViewColumnCellInfo *inf = list->data;
- if (inf->pack == GTK_PACK_START)
- return list;
- }
- }
-
- for (list = current->prev; list; list = list->prev)
- {
- PsppSheetViewColumnCellInfo *inf = list->data;
- if (inf->pack == GTK_PACK_START)
- return list;
- }
-
- return NULL;
-}
-
-gboolean
-_pspp_sheet_view_column_cell_focus (PsppSheetViewColumn *tree_column,
- gint direction,
- gboolean left,
- gboolean right)
-{
- gint count;
- gboolean rtl;
-
- count = _pspp_sheet_view_column_count_special_cells (tree_column);
- rtl = gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL;
-
- /* if we are the current focus column and have multiple editable cells,
- * try to select the next one, else move the focus to the next column
- */
- if (PSPP_SHEET_VIEW (tree_column->tree_view)->priv->focus_column == tree_column)
- {
- if (count > 1)
- {
- GList *next, *prev;
- GList *list = tree_column->cell_list;
- PsppSheetViewColumnCellInfo *info = NULL;
-
- /* find current focussed cell */
- for ( ; list; list = list->next)
- {
- info = list->data;
- if (info->has_focus)
- break;
- }
-
- /* not a focussed cell in the focus column? */
- if (!list || !info || !info->has_focus)
- return FALSE;
-
- if (rtl)
- {
- prev = pspp_sheet_view_column_cell_next (tree_column, list);
- next = pspp_sheet_view_column_cell_prev (tree_column, list);
- }
- else
- {
- next = pspp_sheet_view_column_cell_next (tree_column, list);
- prev = pspp_sheet_view_column_cell_prev (tree_column, list);
- }
-
- info->has_focus = FALSE;
- if (direction > 0 && next)
- {
- info = next->data;
- info->has_focus = TRUE;
- return TRUE;
- }
- else if (direction > 0 && !next && !right)
- {
- /* keep focus on last cell */
- if (rtl)
- info = pspp_sheet_view_column_cell_first (tree_column)->data;
- else
- info = pspp_sheet_view_column_cell_last (tree_column)->data;
-
- info->has_focus = TRUE;
- return TRUE;
- }
- else if (direction < 0 && prev)
- {
- info = prev->data;
- info->has_focus = TRUE;
- return TRUE;
- }
- else if (direction < 0 && !prev && !left)
- {
- /* keep focus on first cell */
- if (rtl)
- info = pspp_sheet_view_column_cell_last (tree_column)->data;
- else
- info = pspp_sheet_view_column_cell_first (tree_column)->data;
-
- info->has_focus = TRUE;
- return TRUE;
- }
- }
- return FALSE;
- }
-
- /* we get focus, if we have multiple editable cells, give the correct one
- * focus
- */
- if (count > 1)
- {
- GList *list = tree_column->cell_list;
-
- /* clear focus first */
- for ( ; list ; list = list->next)
- {
- PsppSheetViewColumnCellInfo *info = list->data;
- if (info->has_focus)
- info->has_focus = FALSE;
- }
-
- list = NULL;
- if (rtl)
- {
- if (direction > 0)
- list = pspp_sheet_view_column_cell_last (tree_column);
- else if (direction < 0)
- list = pspp_sheet_view_column_cell_first (tree_column);
- }
- else
- {
- if (direction > 0)
- list = pspp_sheet_view_column_cell_first (tree_column);
- else if (direction < 0)
- list = pspp_sheet_view_column_cell_last (tree_column);
- }
-
- if (list)
- ((PsppSheetViewColumnCellInfo *) list->data)->has_focus = TRUE;
- }
-
- return TRUE;
-}
-
-void
-_pspp_sheet_view_column_cell_draw_focus (PsppSheetViewColumn *tree_column,
- cairo_t *cr,
- const GdkRectangle *background_area,
- const GdkRectangle *cell_area,
- guint flags)
-{
- gint focus_line_width;
- GtkStateType cell_state;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
- gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
- "focus-line-width", &focus_line_width, NULL);
- if (tree_column->editable_widget)
- {
- /* This function is only called on the editable row when editing.
- */
-#if 0
- gtk_paint_focus (tree_column->tree_view->style,
- window,
- gtk_widget_get_state (tree_column->tree_view),
- NULL,
- tree_column->tree_view,
- "treeview",
- cell_area->x - focus_line_width,
- cell_area->y - focus_line_width,
- cell_area->width + 2 * focus_line_width,
- cell_area->height + 2 * focus_line_width);
-#endif
- }
- else
- {
- GdkRectangle focus_rectangle;
- pspp_sheet_view_column_cell_process_action (tree_column,
- cr,
- background_area,
- cell_area,
- flags,
- CELL_ACTION_FOCUS,
- &focus_rectangle,
- NULL, NULL, NULL);
-
- cell_state = flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
- (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
- (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL));
-
- gtk_paint_focus (gtk_widget_get_style (GTK_WIDGET (tree_column->tree_view)),
- cr,
- cell_state,
- tree_column->tree_view,
- "treeview",
- focus_rectangle.x,
- focus_rectangle.y,
- focus_rectangle.width,
- focus_rectangle.height);
- }
-}
-
-/**
- * pspp_sheet_view_column_cell_is_visible:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns %TRUE if any of the cells packed into the @tree_column are visible.
- * For this to be meaningful, you must first initialize the cells with
- * pspp_sheet_view_column_cell_set_cell_data()
- *
- * Return value: %TRUE, if any of the cells packed into the @tree_column are currently visible
- **/
-gboolean
-pspp_sheet_view_column_cell_is_visible (PsppSheetViewColumn *tree_column)
-{
- GList *list;
-
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), FALSE);
-
- for (list = tree_column->cell_list; list; list = list->next)
- {
- PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
-
- if (gtk_cell_renderer_get_visible (info->cell))
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- * pspp_sheet_view_column_focus_cell:
- * @tree_column: A #PsppSheetViewColumn
- * @cell: A #GtkCellRenderer
- *
- * Sets the current keyboard focus to be at @cell, if the column contains
- * 2 or more editable and activatable cells.
- *
- * Since: 2.2
- **/
-void
-pspp_sheet_view_column_focus_cell (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell)
-{
- GList *list;
- gboolean found_cell = FALSE;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
- g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
-
- if (_pspp_sheet_view_column_count_special_cells (tree_column) < 2)
- return;
-
- for (list = tree_column->cell_list; list; list = list->next)
- {
- PsppSheetViewColumnCellInfo *info = list->data;
-
- if (info->cell == cell)
- {
- info->has_focus = TRUE;
- found_cell = TRUE;
- break;
- }
- }
-
- if (found_cell)
- {
- for (list = tree_column->cell_list; list; list = list->next)
- {
- PsppSheetViewColumnCellInfo *info = list->data;
-
- if (info->cell != cell)
- info->has_focus = FALSE;
- }
-
- /* FIXME: redraw? */
- }
-}
-
-void
-_pspp_sheet_view_column_cell_set_dirty (PsppSheetViewColumn *tree_column)
-{
- GList *list;
-
- for (list = tree_column->cell_list; list; list = list->next)
- {
- PsppSheetViewColumnCellInfo *info = (PsppSheetViewColumnCellInfo *) list->data;
-
- info->requested_width = 0;
- }
- tree_column->dirty = TRUE;
- tree_column->requested_width = -1;
- tree_column->width = 0;
-
- if (tree_column->tree_view &&
- PSPP_SHEET_VIEW (tree_column->tree_view)->priv->resized &&
- gtk_widget_get_realized (tree_column->tree_view))
- {
- PSPP_SHEET_VIEW (tree_column->tree_view)->priv->resized = FALSE;
- _pspp_sheet_view_install_mark_rows_col_dirty (PSPP_SHEET_VIEW (tree_column->tree_view));
- gtk_widget_queue_resize (tree_column->tree_view);
- }
-}
-
-void
-_pspp_sheet_view_column_start_editing (PsppSheetViewColumn *tree_column,
- GtkCellEditable *cell_editable)
-{
- g_return_if_fail (tree_column->editable_widget == NULL);
-
- tree_column->editable_widget = cell_editable;
-}
-
-void
-_pspp_sheet_view_column_stop_editing (PsppSheetViewColumn *tree_column)
-{
- GList *list;
-
- g_return_if_fail (tree_column->editable_widget != NULL);
-
- tree_column->editable_widget = NULL;
- for (list = tree_column->cell_list; list; list = list->next)
- ((PsppSheetViewColumnCellInfo *)list->data)->in_editing_mode = FALSE;
-}
-
-void
-_pspp_sheet_view_column_get_neighbor_sizes (PsppSheetViewColumn *column,
- GtkCellRenderer *cell,
- gint *left,
- gint *right)
-{
- GList *list;
- PsppSheetViewColumnCellInfo *info;
- gint l, r;
- gboolean rtl;
-
- l = r = 0;
-
- list = pspp_sheet_view_column_cell_first (column);
-
- while (list)
- {
- info = (PsppSheetViewColumnCellInfo *)list->data;
-
- list = pspp_sheet_view_column_cell_next (column, list);
-
- if (info->cell == cell)
- break;
-
- if (gtk_cell_renderer_get_visible (info->cell))
- l += info->real_width + column->spacing;
- }
-
- while (list)
- {
- info = (PsppSheetViewColumnCellInfo *)list->data;
-
- list = pspp_sheet_view_column_cell_next (column, list);
-
- if (gtk_cell_renderer_get_visible (info->cell))
- r += info->real_width + column->spacing;
- }
-
- rtl = (gtk_widget_get_direction (GTK_WIDGET (column->tree_view)) == GTK_TEXT_DIR_RTL);
- if (left)
- *left = rtl ? r : l;
-
- if (right)
- *right = rtl ? l : r;
-}
-
-/**
- * pspp_sheet_view_column_cell_get_position:
- * @tree_column: a #PsppSheetViewColumn
- * @cell_renderer: a #GtkCellRenderer
- * @start_pos: return location for the horizontal position of @cell within
- * @tree_column, may be %NULL
- * @width: return location for the width of @cell, may be %NULL
- *
- * Obtains the horizontal position and size of a cell in a column. If the
- * cell is not found in the column, @start_pos and @width are not changed and
- * %FALSE is returned.
- *
- * Return value: %TRUE if @cell belongs to @tree_column.
- */
-gboolean
-pspp_sheet_view_column_cell_get_position (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell_renderer,
- gint *start_pos,
- gint *width)
-{
- GList *list;
- gint current_x = 0;
- gboolean found_cell = FALSE;
- PsppSheetViewColumnCellInfo *cellinfo = NULL;
-
- list = pspp_sheet_view_column_cell_first (tree_column);
- for (; list; list = pspp_sheet_view_column_cell_next (tree_column, list))
- {
- cellinfo = list->data;
- if (cellinfo->cell == cell_renderer)
- {
- found_cell = TRUE;
- break;
- }
-
- if (gtk_cell_renderer_get_visible (cellinfo->cell))
- current_x += cellinfo->real_width;
- }
-
- if (found_cell)
- {
- if (start_pos)
- *start_pos = current_x;
- if (width)
- *width = cellinfo->real_width;
- }
-
- return found_cell;
-}
-
-/**
- * pspp_sheet_view_column_queue_resize:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Flags the column, and the cell renderers added to this column, to have
- * their sizes renegotiated.
- *
- * Since: 2.8
- **/
-void
-pspp_sheet_view_column_queue_resize (PsppSheetViewColumn *tree_column)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column));
-
- if (tree_column->tree_view)
- _pspp_sheet_view_column_cell_set_dirty (tree_column);
-}
-
-/**
- * pspp_sheet_view_column_get_tree_view:
- * @tree_column: A #PsppSheetViewColumn
- *
- * Returns the #PsppSheetView wherein @tree_column has been inserted. If
- * @column is currently not inserted in any tree view, %NULL is
- * returned.
- *
- * Return value: The tree view wherein @column has been inserted if any,
- * %NULL otherwise.
- *
- * Since: 2.12
- */
-GtkWidget *
-pspp_sheet_view_column_get_tree_view (PsppSheetViewColumn *tree_column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (tree_column), NULL);
-
- return tree_column->tree_view;
-}
-
-typedef struct {
- GtkCellLayout *cell_layout;
- GtkCellRenderer *renderer;
- gchar *attr_name;
-} AttributesSubParserData;
-
-static void
-attributes_start_element (GMarkupParseContext *context,
- const gchar *element_name,
- const gchar **names,
- const gchar **values,
- gpointer user_data,
- GError **error)
-{
- AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
- guint i;
-
- if (strcmp (element_name, "attribute") == 0)
- {
- for (i = 0; names[i]; i++)
- if (strcmp (names[i], "name") == 0)
- parser_data->attr_name = g_strdup (values[i]);
- }
- else if (strcmp (element_name, "attributes") == 0)
- return;
- else
- g_warning ("Unsupported tag for GtkCellLayout: %s\n", element_name);
-}
-
-static void
-attributes_text_element (GMarkupParseContext *context,
- const gchar *text,
- gsize text_len,
- gpointer user_data,
- GError **error)
-{
- AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
- glong l;
- gchar *endptr;
- gchar *string;
-
- if (!parser_data->attr_name)
- return;
-
- errno = 0;
- string = g_strndup (text, text_len);
- l = strtol (string, &endptr, 0);
- if (errno || endptr == string)
- {
- g_set_error (error,
- GTK_BUILDER_ERROR,
- GTK_BUILDER_ERROR_INVALID_VALUE,
- "Could not parse integer `%s'",
- string);
- g_free (string);
- return;
- }
- g_free (string);
-
- gtk_cell_layout_add_attribute (parser_data->cell_layout,
- parser_data->renderer,
- parser_data->attr_name, l);
- g_free (parser_data->attr_name);
- parser_data->attr_name = NULL;
-}
-
-static const GMarkupParser attributes_parser =
- {
- attributes_start_element,
- NULL,
- attributes_text_element,
- };
-
-static gboolean
-_cell_layout_buildable_custom_tag_start (GtkBuildable *buildable,
- GtkBuilder *builder,
- GObject *child,
- const gchar *tagname,
- GMarkupParser *parser,
- gpointer *data)
-{
- AttributesSubParserData *parser_data;
-
- if (!child)
- return FALSE;
-
- if (strcmp (tagname, "attributes") == 0)
- {
- parser_data = g_slice_new0 (AttributesSubParserData);
- parser_data->cell_layout = GTK_CELL_LAYOUT (buildable);
- parser_data->renderer = GTK_CELL_RENDERER (child);
- parser_data->attr_name = NULL;
-
- *parser = attributes_parser;
- *data = parser_data;
- return TRUE;
- }
-
- return FALSE;
-}
-
-static void
-_cell_layout_buildable_custom_tag_end (GtkBuildable *buildable,
- GtkBuilder *builder,
- GObject *child,
- const gchar *tagname,
- gpointer *data)
-{
- AttributesSubParserData *parser_data;
-
- parser_data = (AttributesSubParserData*)data;
- g_assert (!parser_data->attr_name);
- g_slice_free (AttributesSubParserData, parser_data);
-}
-
-static void
-_cell_layout_buildable_add_child (GtkBuildable *buildable,
- GtkBuilder *builder,
- GObject *child,
- const gchar *type)
-{
- GtkCellLayoutIface *iface;
-
- g_return_if_fail (GTK_IS_CELL_LAYOUT (buildable));
- g_return_if_fail (GTK_IS_CELL_RENDERER (child));
-
- iface = GTK_CELL_LAYOUT_GET_IFACE (buildable);
- g_return_if_fail (iface->pack_start != NULL);
- iface->pack_start (GTK_CELL_LAYOUT (buildable), GTK_CELL_RENDERER (child), FALSE);
-}
-
-void
-pspp_sheet_view_column_size_request (PsppSheetViewColumn *tree_column,
- GtkRequisition *request)
-{
- GtkWidget *base = GTK_WIDGET (tree_column->tree_view);
- GtkRequisition label_req;
- GtkRequisition align_req;
- GtkRequisition arrow_req;
- GtkRequisition hbox_req;
- GtkStyle **button_style;
-
- if (tree_column->button)
- {
- gtk_widget_get_preferred_size (tree_column->button, NULL, request);
- return;
- }
-
- facade_label_get_size_request (0, 0, base, tree_column->title, &label_req);
- facade_alignment_get_size_request (0, 0, 0, 0, 0, &label_req, &align_req);
- facade_arrow_get_size_request (0, 0, &arrow_req);
-
- facade_hbox_get_base_size_request (0, 2, 2, &hbox_req);
- facade_hbox_add_child_size_request (0, &arrow_req, 0, &hbox_req);
- facade_hbox_add_child_size_request (0, &align_req, 0, &hbox_req);
-
- button_style = &PSPP_SHEET_VIEW (tree_column->tree_view)->priv->button_style;
- if (*button_style == NULL)
- {
- *button_style = facade_get_style (base, GTK_TYPE_BUTTON, 0);
- g_object_ref (*button_style);
- }
- facade_button_get_size_request (0, base, *button_style, &hbox_req, request);
-}
-
-void
-pspp_sheet_view_column_size_allocate (PsppSheetViewColumn *tree_column,
- GtkAllocation *allocation)
-{
- tree_column->allocation = *allocation;
- if (tree_column->button)
- gtk_widget_size_allocate (tree_column->button, allocation);
-}
-
-gboolean
-pspp_sheet_view_column_can_focus (PsppSheetViewColumn *tree_column)
-{
- return tree_column->reorderable || tree_column->clickable;
-}
+++ /dev/null
-/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2011, 2012 Free Software Foundation, Inc.
-
- 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/>. */
-
-/* gtktreeviewcolumn.h
- * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * 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.
- */
-
-#ifndef __PSPP_SHEET_VIEW_COLUMN_H__
-#define __PSPP_SHEET_VIEW_COLUMN_H__
-
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-#define PSPP_TYPE_SHEET_VIEW_COLUMN (pspp_sheet_view_column_get_type ())
-#define PSPP_SHEET_VIEW_COLUMN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PSPP_TYPE_SHEET_VIEW_COLUMN, PsppSheetViewColumn))
-#define PSPP_SHEET_VIEW_COLUMN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PSPP_TYPE_SHEET_VIEW_COLUMN, PsppSheetViewColumnClass))
-#define PSPP_IS_SHEET_VIEW_COLUMN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPP_TYPE_SHEET_VIEW_COLUMN))
-#define PSPP_IS_SHEET_VIEW_COLUMN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPP_TYPE_SHEET_VIEW_COLUMN))
-#define PSPP_SHEET_VIEW_COLUMN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PSPP_TYPE_SHEET_VIEW_COLUMN, PsppSheetViewColumnClass))
-
-typedef struct _PsppSheetViewColumn PsppSheetViewColumn;
-typedef struct _PsppSheetViewColumnClass PsppSheetViewColumnClass;
-
-typedef void (* PsppSheetCellDataFunc) (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell,
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- gpointer data);
-
-
-struct _PsppSheetViewColumn
-{
- GObject parent;
-
- GtkWidget *PSEAL (tree_view);
- GtkWidget *PSEAL (button);
- GtkWidget *PSEAL (child);
- GtkWidget *PSEAL (bin);
- GdkWindow *PSEAL (window);
- GtkCellEditable *PSEAL (editable_widget);
- GtkAlign PSEAL (halign);
- guint PSEAL (property_changed_signal);
- gint PSEAL (spacing);
- GtkAllocation PSEAL (allocation);
-
- /* Sizing fields */
- /* see gtk+/doc/tree-column-sizing.txt for more information on them */
- gint PSEAL (requested_width);
- gint PSEAL (button_request);
- gint PSEAL (resized_width);
- gint PSEAL (width);
- gint PSEAL (fixed_width);
- gint PSEAL (min_width);
- gint PSEAL (max_width);
-
- /* dragging columns */
- gint PSEAL (drag_x);
- gint PSEAL (drag_y);
-
- gchar *PSEAL (title);
- GList *PSEAL (cell_list);
-
- /* Sorting */
- guint PSEAL (sort_clicked_signal);
- guint PSEAL (sort_column_changed_signal);
- gint PSEAL (sort_column_id);
- GtkSortType PSEAL (sort_order);
-
- /* Flags */
- guint PSEAL (visible) : 1;
- guint PSEAL (resizable) : 1;
- guint PSEAL (clickable) : 1;
- guint PSEAL (dirty) : 1;
- guint PSEAL (show_sort_indicator) : 1;
- guint PSEAL (maybe_reordered) : 1;
- guint PSEAL (reorderable) : 1;
- guint PSEAL (use_resized_width) : 1;
- guint PSEAL (expand) : 1;
- guint PSEAL (quick_edit) : 1;
- guint PSEAL (selected) : 1;
- guint PSEAL (selectable) : 1;
- guint PSEAL (row_head) : 1;
- guint PSEAL (tabbable) : 1;
-};
-
-struct _PsppSheetViewColumnClass
-{
- GObjectClass parent_class;
-
- gboolean (*clicked) (PsppSheetViewColumn *tree_column);
- gboolean (*button_press_event) (PsppSheetViewColumn *,
- GdkEventButton *);
-
- /* Padding for future expansion */
- void (*_gtk_reserved1) (void);
- void (*_gtk_reserved2) (void);
- void (*_gtk_reserved3) (void);
- void (*_gtk_reserved4) (void);
-};
-
-GType pspp_sheet_view_column_get_type (void) G_GNUC_CONST;
-PsppSheetViewColumn *pspp_sheet_view_column_new (void);
-PsppSheetViewColumn *pspp_sheet_view_column_new_with_attributes (const gchar *title,
- GtkCellRenderer *cell,
- ...) G_GNUC_NULL_TERMINATED;
-void pspp_sheet_view_column_pack_start (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell,
- gboolean expand);
-void pspp_sheet_view_column_pack_end (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell,
- gboolean expand);
-void pspp_sheet_view_column_clear (PsppSheetViewColumn *tree_column);
-
-GList *pspp_sheet_view_column_get_cell_renderers (PsppSheetViewColumn *tree_column);
-
-void pspp_sheet_view_column_add_attribute (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell_renderer,
- const gchar *attribute,
- gint column);
-void pspp_sheet_view_column_set_attributes (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell_renderer,
- ...) G_GNUC_NULL_TERMINATED;
-void pspp_sheet_view_column_set_cell_data_func (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell_renderer,
- PsppSheetCellDataFunc func,
- gpointer func_data,
- GDestroyNotify destroy);
-void pspp_sheet_view_column_clear_attributes (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell_renderer);
-void pspp_sheet_view_column_set_spacing (PsppSheetViewColumn *tree_column,
- gint spacing);
-gint pspp_sheet_view_column_get_spacing (PsppSheetViewColumn *tree_column);
-void pspp_sheet_view_column_set_visible (PsppSheetViewColumn *tree_column,
- gboolean visible);
-gboolean pspp_sheet_view_column_get_visible (PsppSheetViewColumn *tree_column);
-void pspp_sheet_view_column_set_resizable (PsppSheetViewColumn *tree_column,
- gboolean resizable);
-gboolean pspp_sheet_view_column_get_resizable (PsppSheetViewColumn *tree_column);
-gint pspp_sheet_view_column_get_width (PsppSheetViewColumn *tree_column);
-gint pspp_sheet_view_column_get_fixed_width (PsppSheetViewColumn *tree_column);
-void pspp_sheet_view_column_set_fixed_width (PsppSheetViewColumn *tree_column,
- gint fixed_width);
-void pspp_sheet_view_column_set_min_width (PsppSheetViewColumn *tree_column,
- gint min_width);
-gint pspp_sheet_view_column_get_min_width (PsppSheetViewColumn *tree_column);
-void pspp_sheet_view_column_set_max_width (PsppSheetViewColumn *tree_column,
- gint max_width);
-gint pspp_sheet_view_column_get_max_width (PsppSheetViewColumn *tree_column);
-void pspp_sheet_view_column_clicked (PsppSheetViewColumn *tree_column);
-
-
-
-/* Options for manipulating the column headers
- */
-void pspp_sheet_view_column_set_title (PsppSheetViewColumn *tree_column,
- const gchar *title);
-const gchar * pspp_sheet_view_column_get_title (PsppSheetViewColumn *tree_column);
-void pspp_sheet_view_column_set_expand (PsppSheetViewColumn *tree_column,
- gboolean expand);
-gboolean pspp_sheet_view_column_get_expand (PsppSheetViewColumn *tree_column);
-void pspp_sheet_view_column_set_clickable (PsppSheetViewColumn *tree_column,
- gboolean clickable);
-gboolean pspp_sheet_view_column_get_clickable (PsppSheetViewColumn *tree_column);
-void pspp_sheet_view_column_set_widget (PsppSheetViewColumn *tree_column,
- GtkWidget *widget);
-GtkWidget *pspp_sheet_view_column_get_widget (PsppSheetViewColumn *tree_column);
-void pspp_sheet_view_column_set_alignment (PsppSheetViewColumn *tree_columna,
- GtkAlign xalign);
-GtkAlign pspp_sheet_view_column_get_alignment (PsppSheetViewColumn *tree_column);
-void pspp_sheet_view_column_set_reorderable (PsppSheetViewColumn *tree_column,
- gboolean reorderable);
-gboolean pspp_sheet_view_column_get_reorderable (PsppSheetViewColumn *tree_column);
-
-void pspp_sheet_view_column_set_quick_edit (PsppSheetViewColumn *tree_column,
- gboolean quick_edit);
-gboolean pspp_sheet_view_column_get_quick_edit (PsppSheetViewColumn *tree_column);
-void pspp_sheet_view_column_set_selected (PsppSheetViewColumn *tree_column,
- gboolean selected);
-gboolean pspp_sheet_view_column_get_selected (PsppSheetViewColumn *tree_column);
-
-void pspp_sheet_view_column_set_selectable (PsppSheetViewColumn *tree_column,
- gboolean selectable);
-gboolean pspp_sheet_view_column_get_selectable (PsppSheetViewColumn *tree_column);
-void pspp_sheet_view_column_set_row_head (PsppSheetViewColumn *tree_column,
- gboolean row_head);
-gboolean pspp_sheet_view_column_get_row_head (PsppSheetViewColumn *tree_column);
-void pspp_sheet_view_column_set_tabbable (PsppSheetViewColumn *tree_column,
- gboolean tabbable);
-gboolean pspp_sheet_view_column_get_tabbable (PsppSheetViewColumn *tree_column);
-
-
-
-/* You probably only want to use pspp_sheet_view_column_set_sort_column_id. The
- * other sorting functions exist primarily to let others do their own custom sorting.
- */
-void pspp_sheet_view_column_set_sort_column_id (PsppSheetViewColumn *tree_column,
- gint sort_column_id);
-gint pspp_sheet_view_column_get_sort_column_id (PsppSheetViewColumn *tree_column);
-void pspp_sheet_view_column_set_sort_indicator (PsppSheetViewColumn *tree_column,
- gboolean setting);
-gboolean pspp_sheet_view_column_get_sort_indicator (PsppSheetViewColumn *tree_column);
-void pspp_sheet_view_column_set_sort_order (PsppSheetViewColumn *tree_column,
- GtkSortType order);
-GtkSortType pspp_sheet_view_column_get_sort_order (PsppSheetViewColumn *tree_column);
-
-
-/* These functions are meant primarily for interaction between the PsppSheetView and the column.
- */
-void pspp_sheet_view_column_cell_set_cell_data (PsppSheetViewColumn *tree_column,
- GtkTreeModel *tree_model,
- GtkTreeIter *iter);
-void pspp_sheet_view_column_cell_get_size (PsppSheetViewColumn *tree_column,
- const GdkRectangle *cell_area,
- gint *x_offset,
- gint *y_offset,
- gint *width,
- gint *height);
-gboolean pspp_sheet_view_column_cell_is_visible (PsppSheetViewColumn *tree_column);
-void pspp_sheet_view_column_focus_cell (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell);
-gboolean pspp_sheet_view_column_cell_get_position (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell_renderer,
- gint *start_pos,
- gint *width);
-void pspp_sheet_view_column_queue_resize (PsppSheetViewColumn *tree_column);
-GtkWidget *pspp_sheet_view_column_get_tree_view (PsppSheetViewColumn *tree_column);
-
-void pspp_sheet_view_column_size_request (PsppSheetViewColumn *tree_column,
- GtkRequisition *requisition);
-
-void pspp_sheet_view_column_size_allocate (PsppSheetViewColumn *tree_column,
- GtkAllocation *allocation);
-gboolean pspp_sheet_view_column_can_focus (PsppSheetViewColumn *tree_column);
-
-G_END_DECLS
-
-
-#endif /* __PSPP_SHEET_VIEW_COLUMN_H__ */
+++ /dev/null
-/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2011, 2012, 2013, 2015 Free Software Foundation, Inc.
-
- 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/>. */
-
-/* gtktreeview.c
- * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * 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 "ui/gui/pspp-sheet-private.h"
-
-#include <gtk/gtk.h>
-#include <gdk/gdk.h>
-#include <gdk/gdkkeysyms.h>
-#include <gdk/gdkkeysyms-compat.h>
-#include <string.h>
-
-#include "ui/gui/psppire-marshal.h"
-#include "ui/gui/pspp-sheet-selection.h"
-
-#define P_(STRING) STRING
-#define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
-#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
-
-/* Many keyboard shortcuts for Mac are the same as for X
- * except they use Command key instead of Control (e.g. Cut,
- * Copy, Paste). This symbol is for those simple cases. */
-#ifndef GDK_WINDOWING_QUARTZ
-#define GTK_DEFAULT_ACCEL_MOD_MASK GDK_CONTROL_MASK
-#else
-#define GTK_DEFAULT_ACCEL_MOD_MASK GDK_META_MASK
-#endif
-
-#define PSPP_SHEET_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
-#define PSPP_SHEET_VIEW_PRIORITY_SCROLL_SYNC (PSPP_SHEET_VIEW_PRIORITY_VALIDATE + 2)
-#define PSPP_SHEET_VIEW_TIME_MS_PER_IDLE 30
-#define SCROLL_EDGE_SIZE 15
-#define EXPANDER_EXTRA_PADDING 4
-#define PSPP_SHEET_VIEW_SEARCH_DIALOG_TIMEOUT 5000
-
-/* The "background" areas of all rows/cells add up to cover the entire tree.
- * The background includes all inter-row and inter-cell spacing.
- * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
- * i.e. just the cells, no spacing.
- */
-
-#define BACKGROUND_HEIGHT(tree_view) (tree_view->priv->fixed_height)
-#define CELL_HEIGHT(tree_view, separator) ((BACKGROUND_HEIGHT (tree_view)) - (separator))
-
-/* Translate from bin_window coordinates to rbtree (tree coordinates) and
- * vice versa.
- */
-#define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
-#define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
-
-/* This is in bin_window coordinates */
-#define BACKGROUND_FIRST_PIXEL(tree_view,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, pspp_sheet_view_node_find_offset (tree_view, (node))))
-#define CELL_FIRST_PIXEL(tree_view,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,node) + separator/2)
-
-#define ROW_HEIGHT(tree_view) \
- ((tree_view->priv->fixed_height > 0) ? (tree_view->priv->fixed_height) : (tree_view)->priv->expander_size)
-
-
-typedef struct _PsppSheetViewChild PsppSheetViewChild;
-struct _PsppSheetViewChild
-{
- GtkWidget *widget;
- PsppSheetViewColumn *column;
- int node;
-};
-
-
-typedef struct _TreeViewDragInfo TreeViewDragInfo;
-struct _TreeViewDragInfo
-{
- GdkModifierType start_button_mask;
- GtkTargetList *_unused_source_target_list;
- GdkDragAction source_actions;
-
- GtkTargetList *_unused_dest_target_list;
-
- guint source_set : 1;
- guint dest_set : 1;
-};
-
-
-/* Signals */
-enum
-{
- ROW_ACTIVATED,
- COLUMNS_CHANGED,
- CURSOR_CHANGED,
- MOVE_CURSOR,
- SELECT_ALL,
- UNSELECT_ALL,
- SELECT_CURSOR_ROW,
- TOGGLE_CURSOR_ROW,
- START_INTERACTIVE_SEARCH,
- LAST_SIGNAL
-};
-
-/* Properties */
-enum {
- PROP_0,
- PROP_MODEL,
- PROP_HADJUSTMENT,
- PROP_VADJUSTMENT,
- PROP_HSCROLL_POLICY,
- PROP_VSCROLL_POLICY,
- PROP_HEADERS_VISIBLE,
- PROP_HEADERS_CLICKABLE,
- PROP_REORDERABLE,
- PROP_RULES_HINT,
- PROP_ENABLE_SEARCH,
- PROP_SEARCH_COLUMN,
- PROP_HOVER_SELECTION,
- PROP_RUBBER_BANDING,
- PROP_ENABLE_GRID_LINES,
- PROP_TOOLTIP_COLUMN,
- PROP_SPECIAL_CELLS,
- PROP_FIXED_HEIGHT,
- PROP_FIXED_HEIGHT_SET
-};
-
-/* object signals */
-static void pspp_sheet_view_finalize (GObject *object);
-static void pspp_sheet_view_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-static void pspp_sheet_view_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
-
-static void pspp_sheet_view_dispose (GObject *object);
-
-/* gtkwidget signals */
-static void pspp_sheet_view_realize (GtkWidget *widget);
-static void pspp_sheet_view_unrealize (GtkWidget *widget);
-static void pspp_sheet_view_map (GtkWidget *widget);
-static void pspp_sheet_view_size_request (GtkWidget *widget,
- GtkRequisition *requisition);
-static void pspp_sheet_view_size_allocate (GtkWidget *widget,
- GtkAllocation *allocation);
-static gboolean pspp_sheet_view_draw (GtkWidget *widget,
- cairo_t *cr);
-static gboolean pspp_sheet_view_key_press (GtkWidget *widget,
- GdkEventKey *event);
-static gboolean pspp_sheet_view_key_release (GtkWidget *widget,
- GdkEventKey *event);
-static gboolean pspp_sheet_view_motion (GtkWidget *widget,
- GdkEventMotion *event);
-static gboolean pspp_sheet_view_enter_notify (GtkWidget *widget,
- GdkEventCrossing *event);
-static gboolean pspp_sheet_view_leave_notify (GtkWidget *widget,
- GdkEventCrossing *event);
-static gboolean pspp_sheet_view_button_press (GtkWidget *widget,
- GdkEventButton *event);
-static gboolean pspp_sheet_view_button_release (GtkWidget *widget,
- GdkEventButton *event);
-static gboolean pspp_sheet_view_grab_broken (GtkWidget *widget,
- GdkEventGrabBroken *event);
-
-static void pspp_sheet_view_set_focus_child (GtkContainer *container,
- GtkWidget *child);
-static gint pspp_sheet_view_focus_out (GtkWidget *widget,
- GdkEventFocus *event);
-static gint pspp_sheet_view_focus (GtkWidget *widget,
- GtkDirectionType direction);
-static void pspp_sheet_view_grab_focus (GtkWidget *widget);
-static void pspp_sheet_view_style_updated (GtkWidget *widget);
-static void pspp_sheet_view_grab_notify (GtkWidget *widget,
- gboolean was_grabbed);
-static void pspp_sheet_view_state_changed (GtkWidget *widget,
- GtkStateType previous_state);
-
-/* container signals */
-static void pspp_sheet_view_remove (GtkContainer *container,
- GtkWidget *widget);
-static void pspp_sheet_view_forall (GtkContainer *container,
- gboolean include_internals,
- GtkCallback callback,
- gpointer callback_data);
-
-/* Source side drag signals */
-static void pspp_sheet_view_drag_begin (GtkWidget *widget,
- GdkDragContext *context);
-static void pspp_sheet_view_drag_end (GtkWidget *widget,
- GdkDragContext *context);
-static void pspp_sheet_view_drag_data_get (GtkWidget *widget,
- GdkDragContext *context,
- GtkSelectionData *selection_data,
- guint info,
- guint time);
-static void pspp_sheet_view_drag_data_delete (GtkWidget *widget,
- GdkDragContext *context);
-
-/* Target side drag signals */
-static void pspp_sheet_view_drag_leave (GtkWidget *widget,
- GdkDragContext *context,
- guint time);
-static gboolean pspp_sheet_view_drag_motion (GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time);
-static gboolean pspp_sheet_view_drag_drop (GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- guint time);
-static void pspp_sheet_view_drag_data_received (GtkWidget *widget,
- GdkDragContext *context,
- gint x,
- gint y,
- GtkSelectionData *selection_data,
- guint info,
- guint time);
-
-/* tree_model signals */
-static void pspp_sheet_view_set_adjustments (PsppSheetView *tree_view,
- GtkAdjustment *hadj,
- GtkAdjustment *vadj);
-static gboolean pspp_sheet_view_real_move_cursor (PsppSheetView *tree_view,
- GtkMovementStep step,
- gint count);
-static gboolean pspp_sheet_view_real_select_all (PsppSheetView *tree_view);
-static gboolean pspp_sheet_view_real_unselect_all (PsppSheetView *tree_view);
-static gboolean pspp_sheet_view_real_select_cursor_row (PsppSheetView *tree_view,
- gboolean start_editing,
- PsppSheetSelectMode mode);
-static gboolean pspp_sheet_view_real_toggle_cursor_row (PsppSheetView *tree_view);
-static void pspp_sheet_view_row_changed (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer data);
-static void pspp_sheet_view_row_inserted (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer data);
-static void pspp_sheet_view_row_deleted (GtkTreeModel *model,
- GtkTreePath *path,
- gpointer data);
-static void pspp_sheet_view_rows_reordered (GtkTreeModel *model,
- GtkTreePath *parent,
- GtkTreeIter *iter,
- gint *new_order,
- gpointer data);
-
-/* Incremental reflow */
-static gint validate_row (PsppSheetView *tree_view,
- int node,
- GtkTreeIter *iter,
- GtkTreePath *path);
-static void validate_visible_area (PsppSheetView *tree_view);
-static gboolean validate_rows_handler (PsppSheetView *tree_view);
-static gboolean presize_handler_callback (gpointer data);
-static void install_presize_handler (PsppSheetView *tree_view);
-static void install_scroll_sync_handler (PsppSheetView *tree_view);
-static void pspp_sheet_view_set_top_row (PsppSheetView *tree_view,
- GtkTreePath *path,
- gint offset);
-static void pspp_sheet_view_dy_to_top_row (PsppSheetView *tree_view);
-static void pspp_sheet_view_top_row_to_dy (PsppSheetView *tree_view);
-static void invalidate_empty_focus (PsppSheetView *tree_view);
-
-/* Internal functions */
-static GtkAdjustment *pspp_sheet_view_do_get_hadjustment (PsppSheetView *);
-static GtkAdjustment *pspp_sheet_view_do_get_vadjustment (PsppSheetView *);
-static void pspp_sheet_view_do_set_hadjustment (PsppSheetView *tree_view,
- GtkAdjustment *adjustment);
-static void pspp_sheet_view_do_set_vadjustment (PsppSheetView *tree_view,
- GtkAdjustment *adjustment);
-static void pspp_sheet_view_add_move_binding (GtkBindingSet *binding_set,
- guint keyval,
- guint modmask,
- gboolean add_shifted_binding,
- GtkMovementStep step,
- gint count);
-static void pspp_sheet_view_queue_draw_path (PsppSheetView *tree_view,
- GtkTreePath *path,
- const GdkRectangle *clip_rect);
-static gint pspp_sheet_view_new_column_width (PsppSheetView *tree_view,
- gint i,
- gint *x);
-static void pspp_sheet_view_adjustment_changed (GtkAdjustment *adjustment,
- PsppSheetView *tree_view);
-static void pspp_sheet_view_clamp_node_visible (PsppSheetView *tree_view,
- int node);
-static void pspp_sheet_view_clamp_column_visible (PsppSheetView *tree_view,
- PsppSheetViewColumn *column,
- gboolean focus_to_cell);
-static gboolean pspp_sheet_view_maybe_begin_dragging_row (PsppSheetView *tree_view,
- GdkEventMotion *event);
-static void pspp_sheet_view_focus_to_cursor (PsppSheetView *tree_view);
-static gboolean pspp_sheet_view_move_cursor_up_down (PsppSheetView *tree_view,
- gint count,
- PsppSheetSelectMode mode);
-static void pspp_sheet_view_move_cursor_page_up_down (PsppSheetView *tree_view,
- gint count,
- PsppSheetSelectMode mode);
-static void pspp_sheet_view_move_cursor_left_right (PsppSheetView *tree_view,
- gint count,
- PsppSheetSelectMode mode);
-static void pspp_sheet_view_move_cursor_line_start_end (PsppSheetView *tree_view,
- gint count,
- PsppSheetSelectMode mode);
-static void pspp_sheet_view_move_cursor_tab (PsppSheetView *tree_view,
- gint count);
-static void pspp_sheet_view_move_cursor_start_end (PsppSheetView *tree_view,
- gint count,
- PsppSheetSelectMode mode);
-static void pspp_sheet_view_real_set_cursor (PsppSheetView *tree_view,
- GtkTreePath *path,
- gboolean clear_and_select,
- gboolean clamp_node,
- PsppSheetSelectMode mode);
-static gboolean pspp_sheet_view_has_special_cell (PsppSheetView *tree_view);
-static void pspp_sheet_view_stop_rubber_band (PsppSheetView *tree_view);
-static void update_prelight (PsppSheetView *tree_view,
- int x,
- int y);
-static void initialize_fixed_height_mode (PsppSheetView *tree_view);
-
-/* interactive search */
-static void pspp_sheet_view_ensure_interactive_directory (PsppSheetView *tree_view);
-static void pspp_sheet_view_search_dialog_hide (GtkWidget *search_dialog,
- PsppSheetView *tree_view);
-static void pspp_sheet_view_search_position_func (PsppSheetView *tree_view,
- GtkWidget *search_dialog,
- gpointer user_data);
-static void pspp_sheet_view_search_disable_popdown (GtkEntry *entry,
- GtkMenu *menu,
- gpointer data);
-static void pspp_sheet_view_search_activate (GtkEntry *entry,
- PsppSheetView *tree_view);
-static gboolean pspp_sheet_view_real_search_enable_popdown(gpointer data);
-static void pspp_sheet_view_search_enable_popdown (GtkWidget *widget,
- gpointer data);
-static gboolean pspp_sheet_view_search_delete_event (GtkWidget *widget,
- GdkEventAny *event,
- PsppSheetView *tree_view);
-static gboolean pspp_sheet_view_search_button_press_event (GtkWidget *widget,
- GdkEventButton *event,
- PsppSheetView *tree_view);
-static gboolean pspp_sheet_view_search_scroll_event (GtkWidget *entry,
- GdkEventScroll *event,
- PsppSheetView *tree_view);
-static gboolean pspp_sheet_view_search_key_press_event (GtkWidget *entry,
- GdkEventKey *event,
- PsppSheetView *tree_view);
-static gboolean pspp_sheet_view_search_move (GtkWidget *window,
- PsppSheetView *tree_view,
- gboolean up);
-static gboolean pspp_sheet_view_search_equal_func (GtkTreeModel *model,
- gint column,
- const gchar *key,
- GtkTreeIter *iter,
- gpointer search_data);
-static gboolean pspp_sheet_view_search_iter (GtkTreeModel *model,
- PsppSheetSelection *selection,
- GtkTreeIter *iter,
- const gchar *text,
- gint *count,
- gint n);
-static void pspp_sheet_view_search_init (GtkWidget *entry,
- PsppSheetView *tree_view);
-static void pspp_sheet_view_put (PsppSheetView *tree_view,
- GtkWidget *child_widget,
- GtkTreePath *path,
- PsppSheetViewColumn *column);
-static gboolean pspp_sheet_view_start_editing (PsppSheetView *tree_view,
- GtkTreePath *cursor_path);
-static gboolean pspp_sheet_view_editable_button_press_event (GtkWidget *,
- GdkEventButton *,
- PsppSheetView *);
-static void pspp_sheet_view_editable_clicked (GtkButton *, PsppSheetView *);
-static void pspp_sheet_view_real_start_editing (PsppSheetView *tree_view,
- PsppSheetViewColumn *column,
- GtkTreePath *path,
- GtkCellEditable *cell_editable,
- GdkRectangle *cell_area,
- GdkEvent *event,
- guint flags);
-static gboolean pspp_sheet_view_real_start_interactive_search (PsppSheetView *tree_view,
- gboolean keybinding);
-static gboolean pspp_sheet_view_start_interactive_search (PsppSheetView *tree_view);
-static PsppSheetViewColumn *pspp_sheet_view_get_drop_column (PsppSheetView *tree_view,
- PsppSheetViewColumn *column,
- gint drop_position);
-static void
-pspp_sheet_view_adjust_cell_area (PsppSheetView *tree_view,
- PsppSheetViewColumn *column,
- const GdkRectangle *background_area,
- gboolean subtract_focus_rect,
- GdkRectangle *cell_area);
-static gint pspp_sheet_view_find_offset (PsppSheetView *tree_view,
- gint height,
- int *new_node);
-
-/* GtkBuildable */
-static void pspp_sheet_view_buildable_add_child (GtkBuildable *tree_view,
- GtkBuilder *builder,
- GObject *child,
- const gchar *type);
-static void pspp_sheet_view_buildable_init (GtkBuildableIface *iface);
-
-
-static gboolean scroll_row_timeout (gpointer data);
-static void add_scroll_timeout (PsppSheetView *tree_view);
-static void remove_scroll_timeout (PsppSheetView *tree_view);
-
-static guint tree_view_signals [LAST_SIGNAL] = { 0 };
-
-static GtkBindingSet *edit_bindings;
-
-\f
-
-/* GType Methods
- */
-
-G_DEFINE_TYPE_WITH_CODE (PsppSheetView, pspp_sheet_view, GTK_TYPE_CONTAINER,
- G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
- pspp_sheet_view_buildable_init)
- G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
-
-static void
-pspp_sheet_view_get_preferred_width (GtkWidget *widget,
- gint *minimal_width,
- gint *natural_width)
-{
- GtkRequisition requisition;
-
- pspp_sheet_view_size_request (widget, &requisition);
-
- *minimal_width = *natural_width = requisition.width;
-}
-
-static void
-pspp_sheet_view_get_preferred_height (GtkWidget *widget,
- gint *minimal_height,
- gint *natural_height)
-{
- GtkRequisition requisition;
-
- pspp_sheet_view_size_request (widget, &requisition);
-
- *minimal_height = *natural_height = requisition.height;
-}
-
-static void
-pspp_sheet_view_class_init (PsppSheetViewClass *class)
-{
- GObjectClass *o_class;
- GtkWidgetClass *widget_class;
- GtkContainerClass *container_class;
- GtkBindingSet *binding_set[2];
- int i;
-
- binding_set[0] = gtk_binding_set_by_class (class);
-
- binding_set[1] = gtk_binding_set_new ("PsppSheetViewEditing");
- edit_bindings = binding_set[1];
-
- o_class = (GObjectClass *) class;
- widget_class = (GtkWidgetClass *) class;
- container_class = (GtkContainerClass *) class;
-
- /* GObject signals */
- o_class->set_property = pspp_sheet_view_set_property;
- o_class->get_property = pspp_sheet_view_get_property;
- o_class->finalize = pspp_sheet_view_finalize;
- o_class->dispose = pspp_sheet_view_dispose;
-
- /* GtkWidget signals */
- widget_class->map = pspp_sheet_view_map;
- widget_class->realize = pspp_sheet_view_realize;
- widget_class->unrealize = pspp_sheet_view_unrealize;
- widget_class->get_preferred_width = pspp_sheet_view_get_preferred_width;
- widget_class->get_preferred_height = pspp_sheet_view_get_preferred_height;
- widget_class->size_allocate = pspp_sheet_view_size_allocate;
- widget_class->button_press_event = pspp_sheet_view_button_press;
- widget_class->button_release_event = pspp_sheet_view_button_release;
- widget_class->grab_broken_event = pspp_sheet_view_grab_broken;
- /*widget_class->configure_event = pspp_sheet_view_configure;*/
- widget_class->motion_notify_event = pspp_sheet_view_motion;
- widget_class->draw = pspp_sheet_view_draw;
- widget_class->key_press_event = pspp_sheet_view_key_press;
- widget_class->key_release_event = pspp_sheet_view_key_release;
- widget_class->enter_notify_event = pspp_sheet_view_enter_notify;
- widget_class->leave_notify_event = pspp_sheet_view_leave_notify;
- widget_class->focus_out_event = pspp_sheet_view_focus_out;
- widget_class->drag_begin = pspp_sheet_view_drag_begin;
- widget_class->drag_end = pspp_sheet_view_drag_end;
- widget_class->drag_data_get = pspp_sheet_view_drag_data_get;
- widget_class->drag_data_delete = pspp_sheet_view_drag_data_delete;
- widget_class->drag_leave = pspp_sheet_view_drag_leave;
- widget_class->drag_motion = pspp_sheet_view_drag_motion;
- widget_class->drag_drop = pspp_sheet_view_drag_drop;
- widget_class->drag_data_received = pspp_sheet_view_drag_data_received;
- widget_class->focus = pspp_sheet_view_focus;
- widget_class->grab_focus = pspp_sheet_view_grab_focus;
- widget_class->style_updated = pspp_sheet_view_style_updated;
- widget_class->grab_notify = pspp_sheet_view_grab_notify;
- widget_class->state_changed = pspp_sheet_view_state_changed;
-
- /* GtkContainer signals */
- container_class->remove = pspp_sheet_view_remove;
- container_class->forall = pspp_sheet_view_forall;
- container_class->set_focus_child = pspp_sheet_view_set_focus_child;
-
- class->set_scroll_adjustments = pspp_sheet_view_set_adjustments;
- class->move_cursor = pspp_sheet_view_real_move_cursor;
- class->select_all = pspp_sheet_view_real_select_all;
- class->unselect_all = pspp_sheet_view_real_unselect_all;
- class->select_cursor_row = pspp_sheet_view_real_select_cursor_row;
- class->toggle_cursor_row = pspp_sheet_view_real_toggle_cursor_row;
- class->start_interactive_search = pspp_sheet_view_start_interactive_search;
-
- /* Properties */
-
- g_object_class_install_property (o_class,
- PROP_MODEL,
- g_param_spec_object ("model",
- P_("TreeView Model"),
- P_("The model for the tree view"),
- GTK_TYPE_TREE_MODEL,
- GTK_PARAM_READWRITE));
-
- g_object_class_override_property (o_class, PROP_HADJUSTMENT, "hadjustment");
- g_object_class_override_property (o_class, PROP_VADJUSTMENT, "vadjustment");
- g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
- g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
-
- g_object_class_install_property (o_class,
- PROP_HEADERS_VISIBLE,
- g_param_spec_boolean ("headers-visible",
- P_("Headers Visible"),
- P_("Show the column header buttons"),
- TRUE,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (o_class,
- PROP_HEADERS_CLICKABLE,
- g_param_spec_boolean ("headers-clickable",
- P_("Headers Clickable"),
- P_("Column headers respond to click events"),
- TRUE,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (o_class,
- PROP_REORDERABLE,
- g_param_spec_boolean ("reorderable",
- P_("Reorderable"),
- P_("View is reorderable"),
- FALSE,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (o_class,
- PROP_RULES_HINT,
- g_param_spec_boolean ("rules-hint",
- P_("Rules Hint"),
- P_("Set a hint to the theme engine to draw rows in alternating colors"),
- FALSE,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (o_class,
- PROP_ENABLE_SEARCH,
- g_param_spec_boolean ("enable-search",
- P_("Enable Search"),
- P_("View allows user to search through columns interactively"),
- TRUE,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (o_class,
- PROP_SEARCH_COLUMN,
- g_param_spec_int ("search-column",
- P_("Search Column"),
- P_("Model column to search through during interactive search"),
- -1,
- G_MAXINT,
- -1,
- GTK_PARAM_READWRITE));
-
- /**
- * PsppSheetView:hover-selection:
- *
- * Enables of disables the hover selection mode of @tree_view.
- * Hover selection makes the selected row follow the pointer.
- * Currently, this works only for the selection modes
- * %PSPP_SHEET_SELECTION_SINGLE and %PSPP_SHEET_SELECTION_BROWSE.
- *
- * This mode is primarily intended for treeviews in popups, e.g.
- * in #GtkComboBox or #GtkEntryCompletion.
- *
- * Since: 2.6
- */
- g_object_class_install_property (o_class,
- PROP_HOVER_SELECTION,
- g_param_spec_boolean ("hover-selection",
- P_("Hover Selection"),
- P_("Whether the selection should follow the pointer"),
- FALSE,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (o_class,
- PROP_RUBBER_BANDING,
- g_param_spec_boolean ("rubber-banding",
- P_("Rubber Banding"),
- P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
- FALSE,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (o_class,
- PROP_ENABLE_GRID_LINES,
- g_param_spec_enum ("enable-grid-lines",
- P_("Enable Grid Lines"),
- P_("Whether grid lines should be drawn in the tree view"),
- PSPP_TYPE_SHEET_VIEW_GRID_LINES,
- PSPP_SHEET_VIEW_GRID_LINES_NONE,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (o_class,
- PROP_TOOLTIP_COLUMN,
- g_param_spec_int ("tooltip-column",
- P_("Tooltip Column"),
- P_("The column in the model containing the tooltip texts for the rows"),
- -1,
- G_MAXINT,
- -1,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (o_class,
- PROP_SPECIAL_CELLS,
- g_param_spec_enum ("special-cells",
- P_("Special Cells"),
- P_("Whether rows have special cells."),
- PSPP_TYPE_SHEET_VIEW_SPECIAL_CELLS,
- PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (o_class,
- PROP_FIXED_HEIGHT,
- g_param_spec_int ("fixed-height",
- P_("Fixed Height"),
- P_("Height of a single row. Normally the height of a row is determined automatically. Writing this property sets fixed-height-set to true, preventing this property's value from changing."),
- -1,
- G_MAXINT,
- -1,
- GTK_PARAM_READWRITE));
-
- g_object_class_install_property (o_class,
- PROP_FIXED_HEIGHT_SET,
- g_param_spec_boolean ("fixed-height-set",
- P_("Fixed Height Set"),
- P_("Whether fixed-height was set externally."),
- FALSE,
- GTK_PARAM_READWRITE));
-
- /* Style properties */
-#define _TREE_VIEW_EXPANDER_SIZE 12
-#define _TREE_VIEW_VERTICAL_SEPARATOR 2
-#define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
-
- gtk_widget_class_install_style_property (widget_class,
- g_param_spec_int ("expander-size",
- P_("Expander Size"),
- P_("Size of the expander arrow"),
- 0,
- G_MAXINT,
- _TREE_VIEW_EXPANDER_SIZE,
- GTK_PARAM_READABLE));
-
- gtk_widget_class_install_style_property (widget_class,
- g_param_spec_int ("vertical-separator",
- P_("Vertical Separator Width"),
- P_("Vertical space between cells. Must be an even number"),
- 0,
- G_MAXINT,
- _TREE_VIEW_VERTICAL_SEPARATOR,
- GTK_PARAM_READABLE));
-
- gtk_widget_class_install_style_property (widget_class,
- g_param_spec_int ("horizontal-separator",
- P_("Horizontal Separator Width"),
- P_("Horizontal space between cells. Must be an even number"),
- 0,
- G_MAXINT,
- _TREE_VIEW_HORIZONTAL_SEPARATOR,
- GTK_PARAM_READABLE));
-
- gtk_widget_class_install_style_property (widget_class,
- g_param_spec_boolean ("allow-rules",
- P_("Allow Rules"),
- P_("Allow drawing of alternating color rows"),
- TRUE,
- GTK_PARAM_READABLE));
-
- gtk_widget_class_install_style_property (widget_class,
- g_param_spec_boxed ("even-row-color",
- P_("Even Row Color"),
- P_("Color to use for even rows"),
- GDK_TYPE_COLOR,
- GTK_PARAM_READABLE));
-
- gtk_widget_class_install_style_property (widget_class,
- g_param_spec_boxed ("odd-row-color",
- P_("Odd Row Color"),
- P_("Color to use for odd rows"),
- GDK_TYPE_COLOR,
- GTK_PARAM_READABLE));
-
- gtk_widget_class_install_style_property (widget_class,
- g_param_spec_boolean ("row-ending-details",
- P_("Row Ending details"),
- P_("Enable extended row background theming"),
- FALSE,
- GTK_PARAM_READABLE));
-
- gtk_widget_class_install_style_property (widget_class,
- g_param_spec_int ("grid-line-width",
- P_("Grid line width"),
- P_("Width, in pixels, of the tree view grid lines"),
- 0, G_MAXINT, 1,
- GTK_PARAM_READABLE));
-
- gtk_widget_class_install_style_property (widget_class,
- g_param_spec_int ("tree-line-width",
- P_("Tree line width"),
- P_("Width, in pixels, of the tree view lines"),
- 0, G_MAXINT, 1,
- GTK_PARAM_READABLE));
-
- gtk_widget_class_install_style_property (widget_class,
- g_param_spec_string ("tree-line-pattern",
- P_("Tree line pattern"),
- P_("Dash pattern used to draw the tree view lines"),
- "\1\1",
- GTK_PARAM_READABLE));
-
- /* Signals */
-
- /**
- * PsppSheetView::row-activated:
- * @tree_view: the object on which the signal is emitted
- * @path: the #GtkTreePath for the activated row
- * @column: the #PsppSheetViewColumn in which the activation occurred
- *
- * The "row-activated" signal is emitted when the method
- * pspp_sheet_view_row_activated() is called or the user double clicks
- * a treeview row. It is also emitted when a non-editable row is
- * selected and one of the keys: Space, Shift+Space, Return or
- * Enter is pressed.
- *
- * For selection handling refer to the <link linkend="TreeWidget">tree
- * widget conceptual overview</link> as well as #PsppSheetSelection.
- */
- tree_view_signals[ROW_ACTIVATED] =
- g_signal_new ("row-activated",
- G_TYPE_FROM_CLASS (o_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (PsppSheetViewClass, row_activated),
- NULL, NULL,
- psppire_marshal_VOID__BOXED_OBJECT,
- G_TYPE_NONE, 2,
- GTK_TYPE_TREE_PATH,
- PSPP_TYPE_SHEET_VIEW_COLUMN);
-
- /**
- * PsppSheetView::columns-changed:
- * @tree_view: the object on which the signal is emitted
- *
- * The number of columns of the treeview has changed.
- */
- tree_view_signals[COLUMNS_CHANGED] =
- g_signal_new ("columns-changed",
- G_TYPE_FROM_CLASS (o_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PsppSheetViewClass, columns_changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- /**
- * PsppSheetView::cursor-changed:
- * @tree_view: the object on which the signal is emitted
- *
- * The position of the cursor (focused cell) has changed.
- */
- tree_view_signals[CURSOR_CHANGED] =
- g_signal_new ("cursor-changed",
- G_TYPE_FROM_CLASS (o_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PsppSheetViewClass, cursor_changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- tree_view_signals[MOVE_CURSOR] =
- g_signal_new ("move-cursor",
- G_TYPE_FROM_CLASS (o_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (PsppSheetViewClass, move_cursor),
- NULL, NULL,
- psppire_marshal_BOOLEAN__ENUM_INT,
- G_TYPE_BOOLEAN, 2,
- GTK_TYPE_MOVEMENT_STEP,
- G_TYPE_INT);
-
- tree_view_signals[SELECT_ALL] =
- g_signal_new ("select-all",
- G_TYPE_FROM_CLASS (o_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (PsppSheetViewClass, select_all),
- NULL, NULL,
- psppire_marshal_BOOLEAN__VOID,
- G_TYPE_BOOLEAN, 0);
-
- tree_view_signals[UNSELECT_ALL] =
- g_signal_new ("unselect-all",
- G_TYPE_FROM_CLASS (o_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (PsppSheetViewClass, unselect_all),
- NULL, NULL,
- psppire_marshal_BOOLEAN__VOID,
- G_TYPE_BOOLEAN, 0);
-
- tree_view_signals[SELECT_CURSOR_ROW] =
- g_signal_new ("select-cursor-row",
- G_TYPE_FROM_CLASS (o_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (PsppSheetViewClass, select_cursor_row),
- NULL, NULL,
- psppire_marshal_BOOLEAN__BOOLEAN,
- G_TYPE_BOOLEAN, 2,
- G_TYPE_BOOLEAN, G_TYPE_INT);
-
- tree_view_signals[TOGGLE_CURSOR_ROW] =
- g_signal_new ("toggle-cursor-row",
- G_TYPE_FROM_CLASS (o_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (PsppSheetViewClass, toggle_cursor_row),
- NULL, NULL,
- psppire_marshal_BOOLEAN__VOID,
- G_TYPE_BOOLEAN, 0);
-
- tree_view_signals[START_INTERACTIVE_SEARCH] =
- g_signal_new ("start-interactive-search",
- G_TYPE_FROM_CLASS (o_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (PsppSheetViewClass, start_interactive_search),
- NULL, NULL,
- psppire_marshal_BOOLEAN__VOID,
- G_TYPE_BOOLEAN, 0);
-
- /* Key bindings */
- for (i = 0; i < 2; i++)
- {
- pspp_sheet_view_add_move_binding (binding_set[i], GDK_Up, 0, TRUE,
- GTK_MOVEMENT_DISPLAY_LINES, -1);
- pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Up, 0, TRUE,
- GTK_MOVEMENT_DISPLAY_LINES, -1);
-
- pspp_sheet_view_add_move_binding (binding_set[i], GDK_Down, 0, TRUE,
- GTK_MOVEMENT_DISPLAY_LINES, 1);
- pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Down, 0, TRUE,
- GTK_MOVEMENT_DISPLAY_LINES, 1);
-
- pspp_sheet_view_add_move_binding (binding_set[i], GDK_p, GDK_CONTROL_MASK, FALSE,
- GTK_MOVEMENT_DISPLAY_LINES, -1);
-
- pspp_sheet_view_add_move_binding (binding_set[i], GDK_n, GDK_CONTROL_MASK, FALSE,
- GTK_MOVEMENT_DISPLAY_LINES, 1);
-
- pspp_sheet_view_add_move_binding (binding_set[i], GDK_Home, 0, TRUE,
- GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
- pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Home, 0, TRUE,
- GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
-
- pspp_sheet_view_add_move_binding (binding_set[i], GDK_End, 0, TRUE,
- GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
- pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_End, 0, TRUE,
- GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
-
- pspp_sheet_view_add_move_binding (binding_set[i], GDK_Page_Up, 0, TRUE,
- GTK_MOVEMENT_PAGES, -1);
- pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Page_Up, 0, TRUE,
- GTK_MOVEMENT_PAGES, -1);
-
- pspp_sheet_view_add_move_binding (binding_set[i], GDK_Page_Down, 0, TRUE,
- GTK_MOVEMENT_PAGES, 1);
- pspp_sheet_view_add_move_binding (binding_set[i], GDK_KP_Page_Down, 0, TRUE,
- GTK_MOVEMENT_PAGES, 1);
-
-
- gtk_binding_entry_add_signal (binding_set[i], GDK_Up, GDK_CONTROL_MASK, "move-cursor", 2,
- G_TYPE_ENUM, GTK_MOVEMENT_BUFFER_ENDS,
- G_TYPE_INT, -1);
-
- gtk_binding_entry_add_signal (binding_set[i], GDK_Down, GDK_CONTROL_MASK, "move-cursor", 2,
- G_TYPE_ENUM, GTK_MOVEMENT_BUFFER_ENDS,
- G_TYPE_INT, 1);
-
- gtk_binding_entry_add_signal (binding_set[i], GDK_Right, 0, "move-cursor", 2,
- G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
- G_TYPE_INT, 1);
-
- gtk_binding_entry_add_signal (binding_set[i], GDK_Left, 0, "move-cursor", 2,
- G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
- G_TYPE_INT, -1);
-
- gtk_binding_entry_add_signal (binding_set[i], GDK_Tab, 0, "move-cursor", 2,
- G_TYPE_ENUM, GTK_MOVEMENT_LOGICAL_POSITIONS,
- G_TYPE_INT, 1);
-
- gtk_binding_entry_add_signal (binding_set[i], GDK_Tab, GDK_SHIFT_MASK, "move-cursor", 2,
- G_TYPE_ENUM, GTK_MOVEMENT_LOGICAL_POSITIONS,
- G_TYPE_INT, -1);
-
- gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Right, 0, "move-cursor", 2,
- G_TYPE_ENUM, GTK_MOVEMENT_DISPLAY_LINE_ENDS,
- G_TYPE_INT, 1);
-
- gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Left, 0, "move-cursor", 2,
- G_TYPE_ENUM, GTK_MOVEMENT_DISPLAY_LINE_ENDS,
- G_TYPE_INT, -1);
-
- gtk_binding_entry_add_signal (binding_set[i], GDK_Right, GDK_CONTROL_MASK,
- "move-cursor", 2,
- G_TYPE_ENUM, GTK_MOVEMENT_DISPLAY_LINE_ENDS,
- G_TYPE_INT, 1);
-
- gtk_binding_entry_add_signal (binding_set[i], GDK_Left, GDK_CONTROL_MASK,
- "move-cursor", 2,
- G_TYPE_ENUM, GTK_MOVEMENT_DISPLAY_LINE_ENDS,
- G_TYPE_INT, -1);
-
- gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Right, GDK_CONTROL_MASK,
- "move-cursor", 2,
- G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
- G_TYPE_INT, 1);
-
- gtk_binding_entry_add_signal (binding_set[i], GDK_KP_Left, GDK_CONTROL_MASK,
- "move-cursor", 2,
- G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
- G_TYPE_INT, -1);
-
- gtk_binding_entry_add_signal (binding_set[i], GDK_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
-
- gtk_binding_entry_add_signal (binding_set[i], GDK_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
- }
-
- gtk_binding_entry_add_signal (binding_set[0], GDK_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
- gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
-
- gtk_binding_entry_add_signal (binding_set[0], GDK_a, GDK_CONTROL_MASK, "select-all", 0);
- gtk_binding_entry_add_signal (binding_set[0], GDK_slash, GDK_CONTROL_MASK, "select-all", 0);
-
- gtk_binding_entry_add_signal (binding_set[0], GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
- gtk_binding_entry_add_signal (binding_set[0], GDK_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
-
- gtk_binding_entry_add_signal (binding_set[0], GDK_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
- G_TYPE_BOOLEAN, TRUE,
- G_TYPE_INT, PSPP_SHEET_SELECT_MODE_EXTEND);
- gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
- G_TYPE_BOOLEAN, TRUE,
- G_TYPE_INT, PSPP_SHEET_SELECT_MODE_EXTEND);
-
- gtk_binding_entry_add_signal (binding_set[0], GDK_space, 0, "select-cursor-row", 1,
- G_TYPE_BOOLEAN, TRUE,
- G_TYPE_INT, 0);
- gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Space, 0, "select-cursor-row", 1,
- G_TYPE_BOOLEAN, TRUE,
- G_TYPE_INT, 0);
- gtk_binding_entry_add_signal (binding_set[0], GDK_Return, 0, "select-cursor-row", 1,
- G_TYPE_BOOLEAN, TRUE,
- G_TYPE_INT, 0);
- gtk_binding_entry_add_signal (binding_set[0], GDK_ISO_Enter, 0, "select-cursor-row", 1,
- G_TYPE_BOOLEAN, TRUE,
- G_TYPE_INT, 0);
- gtk_binding_entry_add_signal (binding_set[0], GDK_KP_Enter, 0, "select-cursor-row", 1,
- G_TYPE_BOOLEAN, TRUE,
- G_TYPE_INT, 0);
-
- gtk_binding_entry_add_signal (binding_set[0], GDK_BackSpace, 0, "select-cursor-parent", 0);
- gtk_binding_entry_add_signal (binding_set[0], GDK_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
-
- g_type_class_add_private (o_class, sizeof (PsppSheetViewPrivate));
-}
-
-static void
-pspp_sheet_view_buildable_init (GtkBuildableIface *iface)
-{
- iface->add_child = pspp_sheet_view_buildable_add_child;
-}
-
-static void
-pspp_sheet_view_init (PsppSheetView *tree_view)
-{
- tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, PSPP_TYPE_SHEET_VIEW, PsppSheetViewPrivate);
-
- gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
- gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
-
- tree_view->priv->flags = PSPP_SHEET_VIEW_DRAW_KEYFOCUS
- | PSPP_SHEET_VIEW_HEADERS_VISIBLE;
-
- /* We need some padding */
- tree_view->priv->selected = range_tower_create ();
- tree_view->priv->dy = 0;
- tree_view->priv->cursor_offset = 0;
- tree_view->priv->n_columns = 0;
- tree_view->priv->header_height = 1;
- tree_view->priv->x_drag = 0;
- tree_view->priv->drag_pos = -1;
- tree_view->priv->header_has_focus = FALSE;
- tree_view->priv->pressed_button = -1;
- tree_view->priv->press_start_x = -1;
- tree_view->priv->press_start_y = -1;
- tree_view->priv->reorderable = FALSE;
- tree_view->priv->presize_handler_timer = 0;
- tree_view->priv->scroll_sync_timer = 0;
- tree_view->priv->fixed_height = -1;
- tree_view->priv->fixed_height_set = FALSE;
- pspp_sheet_view_set_adjustments (tree_view, NULL, NULL);
- tree_view->priv->selection = _pspp_sheet_selection_new_with_tree_view (tree_view);
- tree_view->priv->enable_search = TRUE;
- tree_view->priv->search_column = -1;
- tree_view->priv->search_position_func = pspp_sheet_view_search_position_func;
- tree_view->priv->search_equal_func = pspp_sheet_view_search_equal_func;
- tree_view->priv->search_custom_entry_set = FALSE;
- tree_view->priv->typeselect_flush_timeout = 0;
- tree_view->priv->init_hadjust_value = TRUE;
- tree_view->priv->width = 0;
-
- tree_view->priv->hover_selection = FALSE;
-
- tree_view->priv->rubber_banding_enable = FALSE;
-
- tree_view->priv->grid_lines = PSPP_SHEET_VIEW_GRID_LINES_NONE;
-
- tree_view->priv->tooltip_column = -1;
-
- tree_view->priv->special_cells = PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT;
-
- tree_view->priv->post_validation_flag = FALSE;
-
- tree_view->priv->last_button_x = -1;
- tree_view->priv->last_button_y = -1;
-
- tree_view->priv->event_last_x = -10000;
- tree_view->priv->event_last_y = -10000;
-
- tree_view->priv->prelight_node = -1;
- tree_view->priv->rubber_band_start_node = -1;
- tree_view->priv->rubber_band_end_node = -1;
-
- tree_view->priv->anchor_column = NULL;
-
- tree_view->priv->button_style = NULL;
-
- tree_view->dispose_has_run = FALSE;
-
- pspp_sheet_view_do_set_vadjustment (tree_view, NULL);
- pspp_sheet_view_do_set_hadjustment (tree_view, NULL);
- gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (tree_view)),
- GTK_STYLE_CLASS_VIEW);
-}
-
-\f
-
-/* GObject Methods
- */
-
-static void
-pspp_sheet_view_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- PsppSheetView *tree_view;
-
- tree_view = PSPP_SHEET_VIEW (object);
-
- switch (prop_id)
- {
- case PROP_MODEL:
- pspp_sheet_view_set_model (tree_view, g_value_get_object (value));
- break;
- case PROP_HADJUSTMENT:
- pspp_sheet_view_do_set_hadjustment (tree_view, g_value_get_object (value));
- break;
- case PROP_VADJUSTMENT:
- pspp_sheet_view_do_set_vadjustment (tree_view, g_value_get_object (value));
- break;
- case PROP_HSCROLL_POLICY:
- tree_view->priv->hscroll_policy = g_value_get_enum (value);
- gtk_widget_queue_resize (GTK_WIDGET (tree_view));
- break;
- case PROP_VSCROLL_POLICY:
- tree_view->priv->vscroll_policy = g_value_get_enum (value);
- gtk_widget_queue_resize (GTK_WIDGET (tree_view));
- break;
- case PROP_HEADERS_VISIBLE:
- pspp_sheet_view_set_headers_visible (tree_view, g_value_get_boolean (value));
- break;
- case PROP_HEADERS_CLICKABLE:
- pspp_sheet_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
- break;
- case PROP_REORDERABLE:
- pspp_sheet_view_set_reorderable (tree_view, g_value_get_boolean (value));
- break;
- case PROP_RULES_HINT:
- pspp_sheet_view_set_rules_hint (tree_view, g_value_get_boolean (value));
- break;
- case PROP_ENABLE_SEARCH:
- pspp_sheet_view_set_enable_search (tree_view, g_value_get_boolean (value));
- break;
- case PROP_SEARCH_COLUMN:
- pspp_sheet_view_set_search_column (tree_view, g_value_get_int (value));
- break;
- case PROP_HOVER_SELECTION:
- tree_view->priv->hover_selection = g_value_get_boolean (value);
- break;
- case PROP_RUBBER_BANDING:
- tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
- break;
- case PROP_ENABLE_GRID_LINES:
- pspp_sheet_view_set_grid_lines (tree_view, g_value_get_enum (value));
- break;
- case PROP_TOOLTIP_COLUMN:
- pspp_sheet_view_set_tooltip_column (tree_view, g_value_get_int (value));
- break;
- case PROP_SPECIAL_CELLS:
- pspp_sheet_view_set_special_cells (tree_view, g_value_get_enum (value));
- break;
- case PROP_FIXED_HEIGHT:
- pspp_sheet_view_set_fixed_height (tree_view, g_value_get_int (value));
- break;
- case PROP_FIXED_HEIGHT_SET:
- if (g_value_get_boolean (value))
- {
- if (!tree_view->priv->fixed_height_set
- && tree_view->priv->fixed_height >= 0)
- {
- tree_view->priv->fixed_height_set = true;
- g_object_notify (G_OBJECT (tree_view), "fixed-height-set");
- }
- }
- else
- {
- if (tree_view->priv->fixed_height_set)
- {
- tree_view->priv->fixed_height_set = false;
- g_object_notify (G_OBJECT (tree_view), "fixed-height-set");
- install_presize_handler (tree_view);
- }
- }
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-pspp_sheet_view_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- PsppSheetView *tree_view;
-
- tree_view = PSPP_SHEET_VIEW (object);
-
- switch (prop_id)
- {
- case PROP_MODEL:
- g_value_set_object (value, tree_view->priv->model);
- break;
- case PROP_HADJUSTMENT:
- g_value_set_object (value, tree_view->priv->hadjustment);
- break;
- case PROP_VADJUSTMENT:
- g_value_set_object (value, tree_view->priv->vadjustment);
- break;
- case PROP_HSCROLL_POLICY:
- g_value_set_enum (value, tree_view->priv->hscroll_policy);
- break;
- case PROP_VSCROLL_POLICY:
- g_value_set_enum (value, tree_view->priv->vscroll_policy);
- break;
- case PROP_HEADERS_VISIBLE:
- g_value_set_boolean (value, pspp_sheet_view_get_headers_visible (tree_view));
- break;
- case PROP_HEADERS_CLICKABLE:
- g_value_set_boolean (value, pspp_sheet_view_get_headers_clickable (tree_view));
- break;
- case PROP_REORDERABLE:
- g_value_set_boolean (value, tree_view->priv->reorderable);
- break;
- case PROP_RULES_HINT:
- g_value_set_boolean (value, tree_view->priv->has_rules);
- break;
- case PROP_ENABLE_SEARCH:
- g_value_set_boolean (value, tree_view->priv->enable_search);
- break;
- case PROP_SEARCH_COLUMN:
- g_value_set_int (value, tree_view->priv->search_column);
- break;
- case PROP_HOVER_SELECTION:
- g_value_set_boolean (value, tree_view->priv->hover_selection);
- break;
- case PROP_RUBBER_BANDING:
- g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
- break;
- case PROP_ENABLE_GRID_LINES:
- g_value_set_enum (value, tree_view->priv->grid_lines);
- break;
- case PROP_TOOLTIP_COLUMN:
- g_value_set_int (value, tree_view->priv->tooltip_column);
- break;
- case PROP_SPECIAL_CELLS:
- g_value_set_enum (value, tree_view->priv->special_cells);
- break;
- case PROP_FIXED_HEIGHT:
- g_value_set_int (value, pspp_sheet_view_get_fixed_height (tree_view));
- break;
- case PROP_FIXED_HEIGHT_SET:
- g_value_set_boolean (value, tree_view->priv->fixed_height_set);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-pspp_sheet_view_dispose (GObject *object)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (object);
-
- if (tree_view->dispose_has_run)
- return;
-
- tree_view->dispose_has_run = TRUE;
-
- if (tree_view->priv->selection != NULL)
- {
- _pspp_sheet_selection_set_tree_view (tree_view->priv->selection, NULL);
- g_object_unref (tree_view->priv->selection);
- tree_view->priv->selection = NULL;
- }
-
- if (tree_view->priv->hadjustment)
- {
- g_object_unref (tree_view->priv->hadjustment);
- tree_view->priv->hadjustment = NULL;
- }
- if (tree_view->priv->vadjustment)
- {
- g_object_unref (tree_view->priv->vadjustment);
- tree_view->priv->vadjustment = NULL;
- }
-
- if (tree_view->priv->button_style)
- {
- g_object_unref (tree_view->priv->button_style);
- tree_view->priv->button_style = NULL;
- }
-
-
- G_OBJECT_CLASS (pspp_sheet_view_parent_class)->dispose (object);
-}
-
-\f
-
-static void
-pspp_sheet_view_buildable_add_child (GtkBuildable *tree_view,
- GtkBuilder *builder,
- GObject *child,
- const gchar *type)
-{
- pspp_sheet_view_append_column (PSPP_SHEET_VIEW (tree_view), PSPP_SHEET_VIEW_COLUMN (child));
-}
-
-static void
-pspp_sheet_view_finalize (GObject *object)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (object);
-
- pspp_sheet_view_stop_editing (tree_view, TRUE);
-
- if (tree_view->priv->selected != NULL)
- {
- range_tower_destroy (tree_view->priv->selected);
- tree_view->priv->selected = NULL;
- }
-
-
- tree_view->priv->prelight_node = -1;
-
-
- if (tree_view->priv->scroll_to_path != NULL)
- {
- gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
- tree_view->priv->scroll_to_path = NULL;
- }
-
- if (tree_view->priv->drag_dest_row != NULL)
- {
- gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
- tree_view->priv->drag_dest_row = NULL;
- }
-
- if (tree_view->priv->top_row != NULL)
- {
- gtk_tree_row_reference_free (tree_view->priv->top_row);
- tree_view->priv->top_row = NULL;
- }
-
- if (tree_view->priv->column_drop_func_data &&
- tree_view->priv->column_drop_func_data_destroy)
- {
- tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
- tree_view->priv->column_drop_func_data = NULL;
- }
-
- if (tree_view->priv->destroy_count_destroy &&
- tree_view->priv->destroy_count_data)
- {
- tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
- tree_view->priv->destroy_count_data = NULL;
- }
-
- gtk_tree_row_reference_free (tree_view->priv->cursor);
- tree_view->priv->cursor = NULL;
-
- gtk_tree_row_reference_free (tree_view->priv->anchor);
- tree_view->priv->anchor = NULL;
-
- /* destroy interactive search dialog */
- if (tree_view->priv->search_window)
- {
- gtk_widget_destroy (tree_view->priv->search_window);
- tree_view->priv->search_window = NULL;
- tree_view->priv->search_entry = NULL;
- if (tree_view->priv->typeselect_flush_timeout)
- {
- g_source_remove (tree_view->priv->typeselect_flush_timeout);
- tree_view->priv->typeselect_flush_timeout = 0;
- }
- }
-
- if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
- {
- tree_view->priv->search_destroy (tree_view->priv->search_user_data);
- tree_view->priv->search_user_data = NULL;
- }
-
- if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
- {
- tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
- tree_view->priv->search_position_user_data = NULL;
- }
-
- pspp_sheet_view_set_model (tree_view, NULL);
-
-
- G_OBJECT_CLASS (pspp_sheet_view_parent_class)->finalize (object);
-}
-
-\f
-
-/* GtkWidget Methods
- */
-
-/* GtkWidget::map helper */
-static void
-pspp_sheet_view_map_buttons (PsppSheetView *tree_view)
-{
- GList *list;
-
- g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
-
- if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_HEADERS_VISIBLE))
- {
- PsppSheetViewColumn *column;
-
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- column = list->data;
- if (column->button != NULL &&
- gtk_widget_get_visible (column->button) &&
- !gtk_widget_get_mapped (column->button))
- gtk_widget_map (column->button);
- }
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- column = list->data;
- if (column->visible == FALSE || column->window == NULL)
- continue;
- if (column->resizable)
- {
- gdk_window_raise (column->window);
- gdk_window_show (column->window);
- }
- else
- gdk_window_hide (column->window);
- }
- gdk_window_show (tree_view->priv->header_window);
- }
-}
-
-static void
-pspp_sheet_view_map (GtkWidget *widget)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
- GList *tmp_list;
-
- gtk_widget_set_mapped (widget, TRUE);
-
- tmp_list = tree_view->priv->children;
- while (tmp_list)
- {
- PsppSheetViewChild *child = tmp_list->data;
- tmp_list = tmp_list->next;
-
- if (gtk_widget_get_visible (child->widget))
- {
- if (!gtk_widget_get_mapped (child->widget))
- gtk_widget_map (child->widget);
- }
- }
- gdk_window_show (tree_view->priv->bin_window);
-
- pspp_sheet_view_map_buttons (tree_view);
-
- gdk_window_show (gtk_widget_get_window (widget));
-}
-
-static void
-pspp_sheet_view_realize (GtkWidget *widget)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
- GList *tmp_list;
- GdkWindow *window;
- GdkWindowAttr attributes;
- gint attributes_mask;
- GtkAllocation allocation;
-
- gtk_widget_set_realized (widget, TRUE);
-
- gtk_widget_get_allocation (widget, &allocation);
-
- /* Make the main, clipping window */
- attributes.window_type = GDK_WINDOW_CHILD;
- attributes.x = allocation.x;
- attributes.y = allocation.y;
- attributes.width = allocation.width;
- attributes.height = allocation.height;
- attributes.wclass = GDK_INPUT_OUTPUT;
- attributes.visual = gtk_widget_get_visual (widget);
- attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
-
- attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
-
- window = gdk_window_new (gtk_widget_get_parent_window (widget),
- &attributes, attributes_mask);
- gtk_widget_set_window (widget, window);
-
- gtk_widget_register_window (widget, window);
- gtk_widget_get_allocation (widget, &allocation);
-
- /* Make the window for the tree */
- attributes.x = 0;
- attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
- attributes.width = MAX (tree_view->priv->width, allocation.width);
- attributes.height = allocation.height;
- attributes.event_mask = (GDK_EXPOSURE_MASK |
- GDK_SCROLL_MASK |
- GDK_POINTER_MOTION_MASK |
- GDK_ENTER_NOTIFY_MASK |
- GDK_LEAVE_NOTIFY_MASK |
- GDK_BUTTON_PRESS_MASK |
- GDK_BUTTON_RELEASE_MASK |
- gtk_widget_get_events (widget));
-
- tree_view->priv->bin_window = gdk_window_new (window,
- &attributes, attributes_mask);
- gtk_widget_register_window (widget, tree_view->priv->bin_window);
- gtk_widget_get_allocation (widget, &allocation);
-
- /* Make the column header window */
- attributes.x = 0;
- attributes.y = 0;
- attributes.width = MAX (tree_view->priv->width, allocation.width);
- attributes.height = tree_view->priv->header_height;
- attributes.event_mask = (GDK_EXPOSURE_MASK |
- GDK_SCROLL_MASK |
- GDK_BUTTON_PRESS_MASK |
- GDK_BUTTON_RELEASE_MASK |
- GDK_KEY_PRESS_MASK |
- GDK_KEY_RELEASE_MASK |
- gtk_widget_get_events (widget));
-
- tree_view->priv->header_window = gdk_window_new (window,
- &attributes, attributes_mask);
- gtk_widget_register_window (widget, tree_view->priv->header_window);
-
- { /* Ensure Background */
- GtkStyleContext *context;
-
- context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
-
- gtk_style_context_set_background (context, gtk_widget_get_window (GTK_WIDGET (tree_view)));
- gtk_style_context_set_background (context, tree_view->priv->header_window);
- }
-
- tmp_list = tree_view->priv->children;
- while (tmp_list)
- {
- PsppSheetViewChild *child = tmp_list->data;
- tmp_list = tmp_list->next;
-
- gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
- }
-
- for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
- _pspp_sheet_view_column_realize_button (PSPP_SHEET_VIEW_COLUMN (tmp_list->data));
-
- /* Need to call those here, since they create GCs */
- pspp_sheet_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
-
- install_presize_handler (tree_view);
-}
-
-static void
-pspp_sheet_view_unrealize (GtkWidget *widget)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
- PsppSheetViewPrivate *priv = tree_view->priv;
- GList *list;
-
- GTK_WIDGET_CLASS (pspp_sheet_view_parent_class)->unrealize (widget);
-
- if (priv->scroll_timeout != 0)
- {
- g_source_remove (priv->scroll_timeout);
- priv->scroll_timeout = 0;
- }
-
- if (priv->open_dest_timeout != 0)
- {
- g_source_remove (priv->open_dest_timeout);
- priv->open_dest_timeout = 0;
- }
-
- if (priv->presize_handler_timer != 0)
- {
- g_source_remove (priv->presize_handler_timer);
- priv->presize_handler_timer = 0;
- }
-
- if (priv->validate_rows_timer != 0)
- {
- g_source_remove (priv->validate_rows_timer);
- priv->validate_rows_timer = 0;
- }
-
- if (priv->scroll_sync_timer != 0)
- {
- g_source_remove (priv->scroll_sync_timer);
- priv->scroll_sync_timer = 0;
- }
-
- if (priv->typeselect_flush_timeout)
- {
- g_source_remove (priv->typeselect_flush_timeout);
- priv->typeselect_flush_timeout = 0;
- }
-
- for (list = priv->columns; list; list = list->next)
- _pspp_sheet_view_column_unrealize_button (PSPP_SHEET_VIEW_COLUMN (list->data));
-
- gdk_window_set_user_data (priv->bin_window, NULL);
- gdk_window_destroy (priv->bin_window);
- priv->bin_window = NULL;
-
- gdk_window_set_user_data (priv->header_window, NULL);
- gdk_window_destroy (priv->header_window);
- priv->header_window = NULL;
-
- if (priv->drag_window)
- {
- gdk_window_set_user_data (priv->drag_window, NULL);
- gdk_window_destroy (priv->drag_window);
- priv->drag_window = NULL;
- }
-
- if (priv->drag_highlight_window)
- {
- gdk_window_set_user_data (priv->drag_highlight_window, NULL);
- gdk_window_destroy (priv->drag_highlight_window);
- priv->drag_highlight_window = NULL;
- }
-
- if (tree_view->priv->columns != NULL)
- {
- list = tree_view->priv->columns;
- while (list)
- {
- PsppSheetViewColumn *column;
- column = PSPP_SHEET_VIEW_COLUMN (list->data);
- list = list->next;
- pspp_sheet_view_remove_column (tree_view, column);
- }
- tree_view->priv->columns = NULL;
- }
-}
-
-/* GtkWidget::size_request helper */
-static void
-pspp_sheet_view_size_request_columns (PsppSheetView *tree_view)
-{
- GList *list;
-
- tree_view->priv->header_height = 0;
-
- if (tree_view->priv->model)
- {
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- GtkRequisition requisition;
- PsppSheetViewColumn *column = list->data;
-
- pspp_sheet_view_column_size_request (column, &requisition);
- column->button_request = requisition.width;
- tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
- }
- }
-}
-
-
-/* Called only by ::size_request */
-static void
-pspp_sheet_view_update_size (PsppSheetView *tree_view)
-{
- GList *list;
- PsppSheetViewColumn *column;
- gint i;
-
- if (tree_view->priv->model == NULL)
- {
- tree_view->priv->width = 0;
- tree_view->priv->prev_width = 0;
- tree_view->priv->height = 0;
- return;
- }
-
- tree_view->priv->prev_width = tree_view->priv->width;
- tree_view->priv->width = 0;
-
- /* keep this in sync with size_allocate below */
- for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
- {
- gint real_requested_width = 0;
- column = list->data;
- if (!column->visible)
- continue;
-
- if (column->use_resized_width)
- {
- real_requested_width = column->resized_width;
- }
- else
- {
- real_requested_width = column->fixed_width;
- }
-
- if (column->min_width != -1)
- real_requested_width = MAX (real_requested_width, column->min_width);
- if (column->max_width != -1)
- real_requested_width = MIN (real_requested_width, column->max_width);
-
- tree_view->priv->width += real_requested_width;
- }
-
- tree_view->priv->height = tree_view->priv->fixed_height * tree_view->priv->row_count;
-}
-
-static void
-pspp_sheet_view_size_request (GtkWidget *widget,
- GtkRequisition *requisition)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
- GList *tmp_list;
-
- /* we validate some rows initially just to make sure we have some size.
- * In practice, with a lot of static lists, this should get a good width.
- */
- initialize_fixed_height_mode (tree_view);
- pspp_sheet_view_size_request_columns (tree_view);
- pspp_sheet_view_update_size (PSPP_SHEET_VIEW (widget));
-
- requisition->width = tree_view->priv->width;
- requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
-
- tmp_list = tree_view->priv->children;
-
- while (tmp_list)
- {
- PsppSheetViewChild *child = tmp_list->data;
- GtkRequisition child_requisition;
-
- tmp_list = tmp_list->next;
-
- if (gtk_widget_get_visible (child->widget))
- {
- gtk_widget_get_preferred_size (child->widget, NULL, &child_requisition);
- }
- }
-}
-
-static void
-invalidate_column (PsppSheetView *tree_view,
- PsppSheetViewColumn *column)
-{
- gint column_offset = 0;
- GList *list;
- GtkWidget *widget = GTK_WIDGET (tree_view);
- gboolean rtl;
-
- if (!gtk_widget_get_realized (widget))
- return;
-
- rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
- for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
- list;
- list = (rtl ? list->prev : list->next))
- {
- PsppSheetViewColumn *tmpcolumn = list->data;
- if (tmpcolumn == column)
- {
- GdkRectangle invalid_rect;
- GtkAllocation allocation;
-
- gtk_widget_get_allocation (widget, &allocation);
- invalid_rect.x = column_offset;
- invalid_rect.y = 0;
- invalid_rect.width = column->width;
- invalid_rect.height = allocation.height;
-
- gdk_window_invalidate_rect (gtk_widget_get_window (widget), &invalid_rect, TRUE);
- break;
- }
-
- column_offset += tmpcolumn->width;
- }
-}
-
-static void
-invalidate_last_column (PsppSheetView *tree_view)
-{
- GList *last_column;
- gboolean rtl;
-
- rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
- for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
- last_column;
- last_column = (rtl ? last_column->next : last_column->prev))
- {
- if (PSPP_SHEET_VIEW_COLUMN (last_column->data)->visible)
- {
- invalidate_column (tree_view, last_column->data);
- return;
- }
- }
-}
-
-static gint
-pspp_sheet_view_get_real_requested_width_from_column (PsppSheetView *tree_view,
- PsppSheetViewColumn *column)
-{
- gint real_requested_width;
-
- if (column->use_resized_width)
- {
- real_requested_width = column->resized_width;
- }
- else
- {
- real_requested_width = column->fixed_width;
- }
-
- if (column->min_width != -1)
- real_requested_width = MAX (real_requested_width, column->min_width);
- if (column->max_width != -1)
- real_requested_width = MIN (real_requested_width, column->max_width);
-
- return real_requested_width;
-}
-
-static gboolean
-span_intersects (int a0, int a_width,
- int b0, int b_width)
-{
- int a1 = a0 + a_width;
- int b1 = b0 + b_width;
- return (a0 >= b0 && a0 < b1) || (b0 >= a0 && b0 < a1);
-}
-
-/* GtkWidget::size_allocate helper */
-static void
-pspp_sheet_view_size_allocate_columns (GtkWidget *widget,
- gboolean *width_changed)
-{
- PsppSheetView *tree_view;
- GList *list, *first_column, *last_column;
- PsppSheetViewColumn *column;
- GtkAllocation col_allocation;
- GtkAllocation allocation;
- gint width = 0;
- gint extra, extra_per_column;
- gint full_requested_width = 0;
- gint number_of_expand_columns = 0;
- gboolean column_changed = FALSE;
- gboolean rtl;
-
- tree_view = PSPP_SHEET_VIEW (widget);
-
- for (last_column = g_list_last (tree_view->priv->columns);
- last_column && !(PSPP_SHEET_VIEW_COLUMN (last_column->data)->visible);
- last_column = last_column->prev)
- ;
-
- if (last_column == NULL)
- return;
-
- for (first_column = g_list_first (tree_view->priv->columns);
- first_column && !(PSPP_SHEET_VIEW_COLUMN (first_column->data)->visible);
- first_column = first_column->next)
- ;
-
- col_allocation.y = 0;
- col_allocation.height = tree_view->priv->header_height;
-
- rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
-
- /* find out how many extra space and expandable columns we have */
- for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
- {
- column = (PsppSheetViewColumn *)list->data;
-
- if (!column->visible)
- continue;
-
- full_requested_width += pspp_sheet_view_get_real_requested_width_from_column (tree_view, column);
-
- if (column->expand)
- number_of_expand_columns++;
- }
-
- gtk_widget_get_allocation (widget, &allocation);
- extra = MAX (allocation.width - full_requested_width, 0);
- if (number_of_expand_columns > 0)
- extra_per_column = extra/number_of_expand_columns;
- else
- extra_per_column = 0;
-
- for (list = (rtl ? last_column : first_column);
- list != (rtl ? first_column->prev : last_column->next);
- list = (rtl ? list->prev : list->next))
- {
- gint real_requested_width = 0;
- gint old_width;
-
- column = list->data;
- old_width = column->width;
-
- if (!column->visible)
- continue;
-
- /* We need to handle the dragged button specially.
- */
- if (column == tree_view->priv->drag_column)
- {
- GtkAllocation drag_allocation;
- drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
- drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
- drag_allocation.x = 0;
- drag_allocation.y = 0;
- pspp_sheet_view_column_size_allocate (tree_view->priv->drag_column,
- &drag_allocation);
- width += drag_allocation.width;
- continue;
- }
-
- real_requested_width = pspp_sheet_view_get_real_requested_width_from_column (tree_view, column);
-
- col_allocation.x = width;
- column->width = real_requested_width;
-
- if (column->expand)
- {
- if (number_of_expand_columns == 1)
- {
- /* We add the remander to the last column as
- * */
- column->width += extra;
- }
- else
- {
- column->width += extra_per_column;
- extra -= extra_per_column;
- number_of_expand_columns --;
- }
- }
-
- if (column->width != old_width)
- g_object_notify (G_OBJECT (column), "width");
-
- col_allocation.width = column->width;
- width += column->width;
-
- if (column->width > old_width)
- column_changed = TRUE;
-
- pspp_sheet_view_column_size_allocate (column, &col_allocation);
-
- if (column->window)
- gdk_window_move_resize (column->window,
- col_allocation.x + (rtl ? 0 : col_allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
- col_allocation.y,
- TREE_VIEW_DRAG_WIDTH, col_allocation.height);
- }
-
- /* We change the width here. The user might have been resizing columns,
- * so the total width of the tree view changes.
- */
- tree_view->priv->width = width;
- if (width_changed)
- *width_changed = TRUE;
-
- if (column_changed)
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-}
-
-static void
-update_childrens_allocation (PsppSheetView *tree_view)
-{
- GList *tmp_list;
- for (tmp_list = tree_view->priv->children; tmp_list; tmp_list = tmp_list->next)
- {
- PsppSheetViewChild *child = tmp_list->data;
- GtkAllocation allocation;
- GtkTreePath *path;
-
- /* totally ignore our child's requisition */
- path = _pspp_sheet_view_find_path (tree_view, child->node);
- pspp_sheet_view_get_cell_area (tree_view, path, child->column, &allocation);
- gtk_tree_path_free (path);
- gtk_widget_size_allocate (child->widget, &allocation);
- }
-}
-
-static void
-pspp_sheet_view_size_allocate (GtkWidget *widget,
- GtkAllocation *allocation)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
- GList *tmp_list;
- gboolean width_changed = FALSE;
- GtkAllocation old_allocation;
- gtk_widget_get_allocation (widget, &old_allocation);
-
- if (allocation->width != old_allocation.width)
- width_changed = TRUE;
-
- if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)
- allocation->x += allocation->width - tree_view->priv->width ;
-
- gtk_widget_set_allocation (widget, allocation);
-
- /* We size-allocate the columns first because the width of the
- * tree view (used in updating the adjustments below) might change.
- */
- pspp_sheet_view_size_allocate_columns (widget, &width_changed);
-
- gtk_adjustment_set_page_size (tree_view->priv->hadjustment, allocation->width);
- gtk_adjustment_set_page_increment (tree_view->priv->hadjustment, allocation->width * 0.9);
- gtk_adjustment_set_step_increment (tree_view->priv->hadjustment, allocation->width * 0.1);
- gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
- gtk_adjustment_set_upper (tree_view->priv->hadjustment, MAX (gtk_adjustment_get_page_size (tree_view->priv->hadjustment), tree_view->priv->width));
-
- if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)
- {
- if (allocation->width < tree_view->priv->width)
- {
- if (tree_view->priv->init_hadjust_value)
- {
- gtk_adjustment_set_value (tree_view->priv->hadjustment, MAX (tree_view->priv->width - allocation->width, 0));
- tree_view->priv->init_hadjust_value = FALSE;
- }
- else if (allocation->width != old_allocation.width)
- {
- gtk_adjustment_set_value (tree_view->priv->hadjustment, CLAMP (gtk_adjustment_get_value (tree_view->priv->hadjustment) - allocation->width + old_allocation.width, 0, tree_view->priv->width - allocation->width));
- }
- else
- gtk_adjustment_set_value (tree_view->priv->hadjustment, CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - gtk_adjustment_get_value (tree_view->priv->hadjustment)), 0, tree_view->priv->width - allocation->width));
- }
- else
- {
- gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
- tree_view->priv->init_hadjust_value = TRUE;
- }
- }
- else
- if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + allocation->width > tree_view->priv->width)
- gtk_adjustment_set_value (tree_view->priv->hadjustment, MAX (tree_view->priv->width - allocation->width, 0));
-
- gtk_adjustment_changed (tree_view->priv->hadjustment);
-
- gtk_adjustment_set_page_size (tree_view->priv->vadjustment, allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
- gtk_adjustment_set_step_increment (tree_view->priv->vadjustment, gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.1);
- gtk_adjustment_set_page_increment (tree_view->priv->vadjustment, gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.9);
- gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
- gtk_adjustment_set_upper (tree_view->priv->vadjustment, MAX (gtk_adjustment_get_page_size (tree_view->priv->vadjustment), tree_view->priv->height));
-
- gtk_adjustment_changed (tree_view->priv->vadjustment);
-
- /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
- if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
- gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
- else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
- gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
- tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
- else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
- pspp_sheet_view_top_row_to_dy (tree_view);
- else
- pspp_sheet_view_dy_to_top_row (tree_view);
-
- if (gtk_widget_get_realized (widget))
- {
- gdk_window_move_resize (gtk_widget_get_window (widget),
- allocation->x, allocation->y,
- allocation->width, allocation->height);
- gdk_window_move_resize (tree_view->priv->header_window,
- - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
- 0,
- MAX (tree_view->priv->width, allocation->width),
- tree_view->priv->header_height);
- gdk_window_move_resize (tree_view->priv->bin_window,
- - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
- TREE_VIEW_HEADER_HEIGHT (tree_view),
- MAX (tree_view->priv->width, allocation->width),
- allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
- }
-
- if (tree_view->priv->row_count == 0)
- invalidate_empty_focus (tree_view);
-
- if (gtk_widget_get_realized (widget))
- {
- gboolean has_expand_column = FALSE;
- for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
- {
- if (pspp_sheet_view_column_get_expand (PSPP_SHEET_VIEW_COLUMN (tmp_list->data)))
- {
- has_expand_column = TRUE;
- break;
- }
- }
-
- /* This little hack only works if we have an LTR locale, and no column has the */
- if (width_changed)
- {
- if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
- ! has_expand_column)
- invalidate_last_column (tree_view);
- else
- gtk_widget_queue_draw (widget);
- }
- update_childrens_allocation(tree_view);
- }
-
- tree_view->priv->resized = TRUE;
-}
-
-/* Grabs the focus and unsets the PSPP_SHEET_VIEW_DRAW_KEYFOCUS flag */
-static void
-grab_focus_and_unset_draw_keyfocus (PsppSheetView *tree_view)
-{
- GtkWidget *widget = GTK_WIDGET (tree_view);
-
- if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
- gtk_widget_grab_focus (widget);
- PSPP_SHEET_VIEW_UNSET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS);
-}
-
-gboolean
-pspp_sheet_view_node_is_selected (PsppSheetView *tree_view,
- int node)
-{
- return node >= 0 && range_tower_contains (tree_view->priv->selected, node);
-}
-
-void
-pspp_sheet_view_node_select (PsppSheetView *tree_view,
- int node)
-{
- range_tower_set1 (tree_view->priv->selected, node, 1);
-}
-
-void
-pspp_sheet_view_node_unselect (PsppSheetView *tree_view,
- int node)
-{
- range_tower_set0 (tree_view->priv->selected, node, 1);
-}
-
-gint
-pspp_sheet_view_node_next (PsppSheetView *tree_view,
- gint node)
-{
- return node + 1 < tree_view->priv->row_count ? node + 1 : -1;
-}
-
-gint
-pspp_sheet_view_node_prev (PsppSheetView *tree_view,
- gint node)
-{
- return node > 0 ? node - 1 : -1;
-}
-
-static gboolean
-all_columns_selected (PsppSheetView *tree_view)
-{
- GList *list;
-
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- PsppSheetViewColumn *column = list->data;
- if (column->selectable && !column->selected)
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_row_head_clicked (PsppSheetView *tree_view,
- gint node,
- PsppSheetViewColumn *column,
- GdkEventButton *event)
-{
- PsppSheetSelection *selection;
- PsppSheetSelectionMode mode;
- GtkTreePath *path;
- gboolean update_anchor;
- gboolean handled;
- guint modifiers;
-
- g_return_val_if_fail (tree_view != NULL, FALSE);
- g_return_val_if_fail (column != NULL, FALSE);
-
- selection = tree_view->priv->selection;
- mode = pspp_sheet_selection_get_mode (selection);
- if (mode != PSPP_SHEET_SELECTION_RECTANGLE)
- return FALSE;
-
- if (!column->row_head)
- return FALSE;
-
- if (event)
- {
- modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
- if (event->type != GDK_BUTTON_PRESS
- || (modifiers != GDK_CONTROL_MASK && modifiers != GDK_SHIFT_MASK))
- return FALSE;
- }
- else
- modifiers = 0;
-
- path = gtk_tree_path_new_from_indices (node, -1);
- if (event == NULL)
- {
- pspp_sheet_selection_unselect_all (selection);
- pspp_sheet_selection_select_path (selection, path);
- pspp_sheet_selection_select_all_columns (selection);
- update_anchor = TRUE;
- handled = TRUE;
- }
- else if (event->type == GDK_BUTTON_PRESS && event->button == 3)
- {
- if (pspp_sheet_selection_count_selected_rows (selection) <= 1
- || !all_columns_selected (tree_view))
- {
- pspp_sheet_selection_unselect_all (selection);
- pspp_sheet_selection_select_path (selection, path);
- pspp_sheet_selection_select_all_columns (selection);
- update_anchor = TRUE;
- handled = FALSE;
- }
- else
- update_anchor = handled = FALSE;
- }
- else if (event->type == GDK_BUTTON_PRESS && event->button == 1
- && modifiers == GDK_CONTROL_MASK)
- {
- if (!all_columns_selected (tree_view))
- {
- pspp_sheet_selection_unselect_all (selection);
- pspp_sheet_selection_select_all_columns (selection);
- }
-
- if (pspp_sheet_selection_path_is_selected (selection, path))
- pspp_sheet_selection_unselect_path (selection, path);
- else
- pspp_sheet_selection_select_path (selection, path);
- update_anchor = TRUE;
- handled = TRUE;
- }
- else if (event->type == GDK_BUTTON_PRESS && event->button == 1
- && modifiers == GDK_SHIFT_MASK)
- {
- GtkTreeRowReference *anchor = tree_view->priv->anchor;
- GtkTreePath *anchor_path;
-
- if (all_columns_selected (tree_view)
- && gtk_tree_row_reference_valid (anchor))
- {
- update_anchor = FALSE;
- anchor_path = gtk_tree_row_reference_get_path (anchor);
- }
- else
- {
- update_anchor = TRUE;
- anchor_path = gtk_tree_path_copy (path);
- }
-
- pspp_sheet_selection_unselect_all (selection);
- pspp_sheet_selection_select_range (selection, anchor_path, path);
- pspp_sheet_selection_select_all_columns (selection);
-
- gtk_tree_path_free (anchor_path);
-
- handled = TRUE;
- }
- else
- update_anchor = handled = FALSE;
-
- if (update_anchor)
- {
- if (tree_view->priv->anchor)
- gtk_tree_row_reference_free (tree_view->priv->anchor);
- tree_view->priv->anchor =
- gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
- tree_view->priv->model,
- path);
- }
-
- gtk_tree_path_free (path);
- return handled;
-}
-
-static gboolean
-find_click (PsppSheetView *tree_view,
- gint x, gint y,
- gint *node,
- PsppSheetViewColumn **column,
- GdkRectangle *background_area,
- GdkRectangle *cell_area)
-{
- gint y_offset;
- gboolean rtl;
- GList *list;
- gint new_y;
-
- /* find the node that was clicked */
- new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, y);
- if (new_y < 0)
- new_y = 0;
- y_offset = -pspp_sheet_view_find_offset (tree_view, new_y, node);
-
- if (*node < 0)
- return FALSE;
-
- background_area->y = y_offset + y;
- background_area->height = ROW_HEIGHT (tree_view);
- background_area->x = 0;
-
- /* Let the column have a chance at selecting it. */
- rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
- for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
- list; list = (rtl ? list->prev : list->next))
- {
- PsppSheetViewColumn *candidate = list->data;
-
- if (!candidate->visible)
- continue;
-
- background_area->width = candidate->width;
- if ((background_area->x > x) ||
- (background_area->x + background_area->width <= x))
- {
- background_area->x += background_area->width;
- continue;
- }
-
- /* we found the focus column */
-
- pspp_sheet_view_adjust_cell_area (tree_view, candidate, background_area,
- TRUE, cell_area);
- *column = candidate;
- return TRUE;
- }
-
- return FALSE;
-}
-
-static gboolean
-pspp_sheet_view_button_press (GtkWidget *widget,
- GdkEventButton *event)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
- GList *list;
- PsppSheetViewColumn *column = NULL;
- gint i;
- GdkRectangle background_area;
- GdkRectangle cell_area;
- gboolean rtl;
-
- rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
- pspp_sheet_view_stop_editing (tree_view, FALSE);
-
-
- /* Because grab_focus can cause reentrancy, we delay grab_focus until after
- * we're done handling the button press.
- */
-
- if (event->window == tree_view->priv->bin_window)
- {
- int node;
- GtkTreePath *path;
- gint dval;
- gint pre_val, aft_val;
- PsppSheetViewColumn *column = NULL;
- GtkCellRenderer *focus_cell = NULL;
- gboolean row_double_click = FALSE;
-
- /* Empty tree? */
- if (tree_view->priv->row_count == 0)
- {
- grab_focus_and_unset_draw_keyfocus (tree_view);
- return TRUE;
- }
-
- if (!find_click (tree_view, event->x, event->y, &node, &column,
- &background_area, &cell_area))
- {
- grab_focus_and_unset_draw_keyfocus (tree_view);
- return FALSE;
- }
-
- tree_view->priv->focus_column = column;
-
- if (pspp_sheet_view_row_head_clicked (tree_view, node, column, event))
- return TRUE;
-
- /* select */
- pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
-
- path = _pspp_sheet_view_find_path (tree_view, node);
-
- /* we only handle selection modifications on the first button press
- */
- if (event->type == GDK_BUTTON_PRESS)
- {
- PsppSheetSelectionMode mode = 0;
-
- if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
- mode |= PSPP_SHEET_SELECT_MODE_TOGGLE;
- if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
- mode |= PSPP_SHEET_SELECT_MODE_EXTEND;
-
- focus_cell = _pspp_sheet_view_column_get_cell_at_pos (column, event->x - background_area.x);
- if (focus_cell)
- pspp_sheet_view_column_focus_cell (column, focus_cell);
-
- if (event->state & GDK_CONTROL_MASK)
- {
- pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE, mode);
- pspp_sheet_view_real_toggle_cursor_row (tree_view);
- }
- else if (event->state & GDK_SHIFT_MASK)
- {
- pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE, mode);
- pspp_sheet_view_real_select_cursor_row (tree_view, FALSE, mode);
- }
- else
- {
- pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE, 0);
- }
-
- if (tree_view->priv->anchor_column == NULL ||
- !(event->state & GDK_SHIFT_MASK))
- tree_view->priv->anchor_column = column;
- pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection);
- pspp_sheet_selection_select_column_range (tree_view->priv->selection,
- tree_view->priv->anchor_column,
- column);
- }
-
- /* the treeview may have been scrolled because of _set_cursor,
- * correct here
- */
-
- aft_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
- dval = pre_val - aft_val;
-
- cell_area.y += dval;
- background_area.y += dval;
-
- /* Save press to possibly begin a drag
- */
- if (!tree_view->priv->in_grab &&
- tree_view->priv->pressed_button < 0)
- {
- tree_view->priv->pressed_button = event->button;
- tree_view->priv->press_start_x = event->x;
- tree_view->priv->press_start_y = event->y;
- tree_view->priv->press_start_node = node;
-
- if (tree_view->priv->rubber_banding_enable
- && (tree_view->priv->selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
- tree_view->priv->selection->type == PSPP_SHEET_SELECTION_RECTANGLE))
- {
- tree_view->priv->press_start_y += tree_view->priv->dy;
- tree_view->priv->rubber_band_x = event->x;
- tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
- tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
-
- if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
- tree_view->priv->rubber_band_ctrl = TRUE;
- if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
- tree_view->priv->rubber_band_shift = TRUE;
-
- }
- }
-
- /* Test if a double click happened on the same row. */
- if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
- {
- int double_click_time, double_click_distance;
-
- g_object_get (gtk_settings_get_for_screen (
- gtk_widget_get_screen (widget)),
- "gtk-double-click-time", &double_click_time,
- "gtk-double-click-distance", &double_click_distance,
- NULL);
-
- /* Same conditions as _gdk_event_button_generate */
- if (tree_view->priv->last_button_x != -1 &&
- (event->time < tree_view->priv->last_button_time + double_click_time) &&
- (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
- (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
- {
- /* We do no longer compare paths of this row and the
- * row clicked previously. We use the double click
- * distance to decide whether this is a valid click,
- * allowing the mouse to slightly move over another row.
- */
- row_double_click = TRUE;
-
- tree_view->priv->last_button_time = 0;
- tree_view->priv->last_button_x = -1;
- tree_view->priv->last_button_y = -1;
- }
- else
- {
- tree_view->priv->last_button_time = event->time;
- tree_view->priv->last_button_x = event->x;
- tree_view->priv->last_button_y = event->y;
- }
- }
-
- if (row_double_click)
- {
- gtk_grab_remove (widget);
- pspp_sheet_view_row_activated (tree_view, path, column);
-
- if (tree_view->priv->pressed_button == event->button)
- tree_view->priv->pressed_button = -1;
- }
-
- gtk_tree_path_free (path);
-
- /* If we activated the row through a double click we don't want to grab
- * focus back, as moving focus to another widget is pretty common.
- */
- if (!row_double_click)
- grab_focus_and_unset_draw_keyfocus (tree_view);
-
- return TRUE;
- }
-
- /* We didn't click in the window. Let's check to see if we clicked on a column resize window.
- */
- for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
- {
- column = list->data;
- if (event->window == column->window &&
- column->resizable &&
- column->window)
- {
- gpointer drag_data;
-
- if (GDK_GRAB_SUCCESS != gdk_device_grab (event->device,
- column->window,
- GDK_OWNERSHIP_NONE,
- FALSE,
- GDK_POINTER_MOTION_HINT_MASK |
- GDK_BUTTON1_MOTION_MASK |
- GDK_BUTTON_RELEASE_MASK,
- NULL, event->time))
- return FALSE;
-
- gtk_grab_add (widget);
- PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_RESIZE);
- column->resized_width = column->width;
-
- /* block attached dnd signal handler */
- drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
- if (drag_data)
- g_signal_handlers_block_matched (widget,
- G_SIGNAL_MATCH_DATA,
- 0, 0, NULL, NULL,
- drag_data);
-
- tree_view->priv->drag_pos = i;
- tree_view->priv->x_drag = column->allocation.x + (rtl ? 0 : column->allocation.width);
-
- if (!gtk_widget_has_focus (widget))
- gtk_widget_grab_focus (widget);
-
- return TRUE;
- }
- }
- return FALSE;
-}
-
-/* GtkWidget::button_release_event helper */
-static gboolean
-pspp_sheet_view_button_release_drag_column (GtkWidget *widget,
- GdkEventButton *event)
-{
- PsppSheetView *tree_view;
- GList *l;
- gboolean rtl;
-
- tree_view = PSPP_SHEET_VIEW (widget);
-
- rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
- gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
- gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
-
- /* Move the button back */
- g_return_val_if_fail (tree_view->priv->drag_column->button, FALSE);
-
- g_object_ref (tree_view->priv->drag_column->button);
- gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
- gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
- gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
- g_object_unref (tree_view->priv->drag_column->button);
- gtk_widget_queue_resize (widget);
- if (tree_view->priv->drag_column->resizable)
- {
- gdk_window_raise (tree_view->priv->drag_column->window);
- gdk_window_show (tree_view->priv->drag_column->window);
- }
- else
- gdk_window_hide (tree_view->priv->drag_column->window);
-
- gtk_widget_grab_focus (tree_view->priv->drag_column->button);
-
- if (rtl)
- {
- if (tree_view->priv->cur_reorder &&
- tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
- pspp_sheet_view_move_column_after (tree_view, tree_view->priv->drag_column,
- tree_view->priv->cur_reorder->right_column);
- }
- else
- {
- if (tree_view->priv->cur_reorder &&
- tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
- pspp_sheet_view_move_column_after (tree_view, tree_view->priv->drag_column,
- tree_view->priv->cur_reorder->left_column);
- }
- tree_view->priv->drag_column = NULL;
- gdk_window_hide (tree_view->priv->drag_window);
-
- for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
- g_slice_free (PsppSheetViewColumnReorder, l->data);
- g_list_free (tree_view->priv->column_drag_info);
- tree_view->priv->column_drag_info = NULL;
- tree_view->priv->cur_reorder = NULL;
-
- if (tree_view->priv->drag_highlight_window)
- gdk_window_hide (tree_view->priv->drag_highlight_window);
-
- /* Reset our flags */
- tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
- PSPP_SHEET_VIEW_UNSET_FLAG (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_DRAG);
-
- return TRUE;
-}
-
-/* GtkWidget::button_release_event helper */
-static gboolean
-pspp_sheet_view_button_release_column_resize (GtkWidget *widget,
- GdkEventButton *event)
-{
- PsppSheetView *tree_view;
- gpointer drag_data;
-
- tree_view = PSPP_SHEET_VIEW (widget);
-
- tree_view->priv->drag_pos = -1;
-
- /* unblock attached dnd signal handler */
- drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
- if (drag_data)
- g_signal_handlers_unblock_matched (widget,
- G_SIGNAL_MATCH_DATA,
- 0, 0, NULL, NULL,
- drag_data);
-
- PSPP_SHEET_VIEW_UNSET_FLAG (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_RESIZE);
- gtk_grab_remove (widget);
- gdk_device_ungrab (event->device, event->time);
-
- return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_button_release_edit (PsppSheetView *tree_view,
- GdkEventButton *event)
-{
- GtkCellEditable *cell_editable;
- gchar *path_string;
- GtkTreePath *path;
- gint left, right;
- GtkTreeIter iter;
- PsppSheetViewColumn *column;
- GdkRectangle background_area;
- GdkRectangle cell_area;
- GdkRectangle area;
- guint modifiers;
- guint flags;
- int node;
-
- if (event->window != tree_view->priv->bin_window)
- return FALSE;
-
- /* Ignore a released button, if that button wasn't depressed */
- if (tree_view->priv->pressed_button != event->button)
- return FALSE;
-
- if (!find_click (tree_view, event->x, event->y, &node, &column, &background_area,
- &cell_area))
- return FALSE;
-
- /* decide if we edit */
- path = _pspp_sheet_view_find_path (tree_view, node);
- modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
- if (event->button != 1 || modifiers)
- return FALSE;
-
- gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
- pspp_sheet_view_column_cell_set_cell_data (column,
- tree_view->priv->model,
- &iter);
-
- if (!pspp_sheet_view_column_get_quick_edit (column)
- && _pspp_sheet_view_column_has_editable_cell (column))
- return FALSE;
-
- flags = 0; /* FIXME: get the right flags */
- path_string = gtk_tree_path_to_string (path);
-
- if (!_pspp_sheet_view_column_cell_event (column,
- &cell_editable,
- (GdkEvent *)event,
- path_string,
- &background_area,
- &cell_area, flags))
- return FALSE;
-
- if (cell_editable == NULL)
- return FALSE;
-
- pspp_sheet_view_real_set_cursor (tree_view, path,
- TRUE, TRUE, 0); /* XXX mode? */
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-
- area = cell_area;
- _pspp_sheet_view_column_get_neighbor_sizes (
- column, _pspp_sheet_view_column_get_edited_cell (column), &left, &right);
-
- area.x += left;
- area.width -= right + left;
-
- pspp_sheet_view_real_start_editing (tree_view,
- column,
- path,
- cell_editable,
- &area,
- (GdkEvent *)event,
- flags);
- g_free (path_string);
- gtk_tree_path_free (path);
- return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_button_release (GtkWidget *widget,
- GdkEventButton *event)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-
- pspp_sheet_view_stop_editing (tree_view, FALSE);
- if (tree_view->priv->rubber_band_status != RUBBER_BAND_ACTIVE
- && pspp_sheet_view_button_release_edit (tree_view, event))
- {
- if (tree_view->priv->pressed_button == event->button)
- tree_view->priv->pressed_button = -1;
-
- tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
- return TRUE;
- }
-
- if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_DRAG))
- return pspp_sheet_view_button_release_drag_column (widget, event);
-
- if (tree_view->priv->rubber_band_status)
- pspp_sheet_view_stop_rubber_band (tree_view);
-
- if (tree_view->priv->pressed_button == event->button)
- tree_view->priv->pressed_button = -1;
-
- if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_RESIZE))
- return pspp_sheet_view_button_release_column_resize (widget, event);
-
- return FALSE;
-}
-
-static gboolean
-pspp_sheet_view_grab_broken (GtkWidget *widget,
- GdkEventGrabBroken *event)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-
- if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_DRAG))
- pspp_sheet_view_button_release_drag_column (widget, (GdkEventButton *)event);
-
- if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_RESIZE))
- pspp_sheet_view_button_release_column_resize (widget, (GdkEventButton *)event);
-
- return TRUE;
-}
-
-/* GtkWidget::motion_event function set.
- */
-
-static void
-do_prelight (PsppSheetView *tree_view,
- int node,
- /* these are in bin_window coords */
- gint x,
- gint y)
-{
- int prev_node = tree_view->priv->prelight_node;
-
- if (prev_node != node)
- {
- tree_view->priv->prelight_node = node;
-
- if (prev_node >= 0)
- _pspp_sheet_view_queue_draw_node (tree_view, prev_node, NULL);
-
- if (node >= 0)
- _pspp_sheet_view_queue_draw_node (tree_view, node, NULL);
- }
-}
-
-
-static void
-prelight_or_select (PsppSheetView *tree_view,
- int node,
- /* these are in bin_window coords */
- gint x,
- gint y)
-{
- PsppSheetSelectionMode mode = pspp_sheet_selection_get_mode (tree_view->priv->selection);
-
- if (tree_view->priv->hover_selection &&
- (mode == PSPP_SHEET_SELECTION_SINGLE || mode == PSPP_SHEET_SELECTION_BROWSE) &&
- !(tree_view->priv->edited_column &&
- tree_view->priv->edited_column->editable_widget))
- {
- if (node >= 0)
- {
- if (!pspp_sheet_view_node_is_selected (tree_view, node))
- {
- GtkTreePath *path;
-
- path = _pspp_sheet_view_find_path (tree_view, node);
- pspp_sheet_selection_select_path (tree_view->priv->selection, path);
- if (pspp_sheet_view_node_is_selected (tree_view, node))
- {
- PSPP_SHEET_VIEW_UNSET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS);
- pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, FALSE, 0); /* XXX mode? */
- }
- gtk_tree_path_free (path);
- }
- }
-
- else if (mode == PSPP_SHEET_SELECTION_SINGLE)
- pspp_sheet_selection_unselect_all (tree_view->priv->selection);
- }
-
- do_prelight (tree_view, node, x, y);
-}
-
-static void
-ensure_unprelighted (PsppSheetView *tree_view)
-{
- do_prelight (tree_view,
- -1,
- -1000, -1000); /* coords not possibly over an arrow */
-
- g_assert (tree_view->priv->prelight_node < 0);
-}
-
-static void
-update_prelight (PsppSheetView *tree_view,
- gint x,
- gint y)
-{
- int new_y;
- int node;
-
- if (tree_view->priv->row_count == 0)
- return;
-
- if (x == -10000)
- {
- ensure_unprelighted (tree_view);
- return;
- }
-
- new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
- if (new_y < 0)
- new_y = 0;
-
- pspp_sheet_view_find_offset (tree_view, new_y, &node);
-
- if (node >= 0)
- prelight_or_select (tree_view, node, x, y);
-}
-
-
-
-
-/* Our motion arrow is either a box (in the case of the original spot)
- * or an arrow. It is expander_size wide.
- */
-/*
- * 11111111111111
- * 01111111111110
- * 00111111111100
- * 00011111111000
- * 00001111110000
- * 00000111100000
- * 00000111100000
- * 00000111100000
- * ~ ~ ~ ~ ~ ~ ~
- * 00000111100000
- * 00000111100000
- * 00000111100000
- * 00001111110000
- * 00011111111000
- * 00111111111100
- * 01111111111110
- * 11111111111111
- */
-
-static void
-pspp_sheet_view_motion_draw_column_motion_arrow (PsppSheetView *tree_view)
-{
-}
-
-static gboolean
-pspp_sheet_view_motion_resize_column (GtkWidget *widget,
- GdkEventMotion *event)
-{
- gint x;
- gint new_width;
- PsppSheetViewColumn *column;
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-
- column = pspp_sheet_view_get_column (tree_view, tree_view->priv->drag_pos);
-
- if (event->is_hint || event->window != gtk_widget_get_window (widget))
- gtk_widget_get_pointer (widget, &x, NULL);
- else
- x = event->x;
-
- if (tree_view->priv->hadjustment)
- x += gtk_adjustment_get_value (tree_view->priv->hadjustment);
-
- new_width = pspp_sheet_view_new_column_width (tree_view,
- tree_view->priv->drag_pos, &x);
- if (x != tree_view->priv->x_drag &&
- (new_width != column->fixed_width))
- {
- column->use_resized_width = TRUE;
- column->resized_width = new_width;
-#if 0
- if (column->expand)
- column->resized_width -= tree_view->priv->last_extra_space_per_column;
-#endif
- gtk_widget_queue_resize (widget);
- }
-
- return FALSE;
-}
-
-
-static void
-pspp_sheet_view_update_current_reorder (PsppSheetView *tree_view)
-{
- PsppSheetViewColumnReorder *reorder = NULL;
- GList *list;
- gint mouse_x;
-
- gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
- for (list = tree_view->priv->column_drag_info; list; list = list->next)
- {
- reorder = (PsppSheetViewColumnReorder *) list->data;
- if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
- break;
- reorder = NULL;
- }
-
- /* if (reorder && reorder == tree_view->priv->cur_reorder)
- return;*/
-
- tree_view->priv->cur_reorder = reorder;
- pspp_sheet_view_motion_draw_column_motion_arrow (tree_view);
-}
-
-static void
-pspp_sheet_view_vertical_autoscroll (PsppSheetView *tree_view)
-{
- GdkRectangle visible_rect;
- gint y;
- gint offset;
- gfloat value;
-
- gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
- y += tree_view->priv->dy;
-
- pspp_sheet_view_get_visible_rect (tree_view, &visible_rect);
-
- /* see if we are near the edge. */
- offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
- if (offset > 0)
- {
- offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
- if (offset < 0)
- return;
- }
-
- value = CLAMP (gtk_adjustment_get_value (tree_view->priv->vadjustment) + offset, 0.0,
- gtk_adjustment_get_upper (tree_view->priv->vadjustment) - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
- gtk_adjustment_set_value (tree_view->priv->vadjustment, value);
-}
-
-static gboolean
-pspp_sheet_view_horizontal_autoscroll (PsppSheetView *tree_view)
-{
- GdkRectangle visible_rect;
- gint x;
- gint offset;
- gfloat value;
-
- gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
-
- pspp_sheet_view_get_visible_rect (tree_view, &visible_rect);
-
- /* See if we are near the edge. */
- offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
- if (offset > 0)
- {
- offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
- if (offset < 0)
- return TRUE;
- }
- offset = offset/3;
-
- value = CLAMP (gtk_adjustment_get_value (tree_view->priv->hadjustment) + offset,
- 0.0, gtk_adjustment_get_upper (tree_view->priv->hadjustment) - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
- gtk_adjustment_set_value (tree_view->priv->hadjustment, value);
-
- return TRUE;
-
-}
-
-static gboolean
-pspp_sheet_view_motion_drag_column (GtkWidget *widget,
- GdkEventMotion *event)
-{
- PsppSheetView *tree_view = (PsppSheetView *) widget;
- PsppSheetViewColumn *column = tree_view->priv->drag_column;
- gint x, y;
- GtkAllocation allocation;
-
- /* Sanity Check */
- if ((column == NULL) ||
- (event->window != tree_view->priv->drag_window))
- return FALSE;
-
- /* Handle moving the header */
- gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
- gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
- x = CLAMP (x + (gint)event->x - column->drag_x, 0,
- MAX (tree_view->priv->width, allocation.width) - column->allocation.width);
- gdk_window_move (tree_view->priv->drag_window, x, y);
-
- /* autoscroll, if needed */
- pspp_sheet_view_horizontal_autoscroll (tree_view);
- /* Update the current reorder position and arrow; */
- pspp_sheet_view_update_current_reorder (tree_view);
-
- return TRUE;
-}
-
-static void
-pspp_sheet_view_stop_rubber_band (PsppSheetView *tree_view)
-{
- remove_scroll_timeout (tree_view);
- gtk_grab_remove (GTK_WIDGET (tree_view));
-
- if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
- {
- GtkTreePath *tmp_path;
-
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-
- /* The anchor path should be set to the start path */
- tmp_path = _pspp_sheet_view_find_path (tree_view,
- tree_view->priv->rubber_band_start_node);
-
- if (tree_view->priv->anchor)
- gtk_tree_row_reference_free (tree_view->priv->anchor);
-
- tree_view->priv->anchor =
- gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
- tree_view->priv->model,
- tmp_path);
-
- gtk_tree_path_free (tmp_path);
-
- /* ... and the cursor to the end path */
- tmp_path = _pspp_sheet_view_find_path (tree_view,
- tree_view->priv->rubber_band_end_node);
- pspp_sheet_view_real_set_cursor (PSPP_SHEET_VIEW (tree_view), tmp_path, FALSE, FALSE, 0); /* XXX mode? */
- gtk_tree_path_free (tmp_path);
-
- _pspp_sheet_selection_emit_changed (tree_view->priv->selection);
- }
-
- /* Clear status variables */
- tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
- tree_view->priv->rubber_band_shift = 0;
- tree_view->priv->rubber_band_ctrl = 0;
-
- tree_view->priv->rubber_band_start_node = -1;
- tree_view->priv->rubber_band_end_node = -1;
-}
-
-static void
-pspp_sheet_view_update_rubber_band_selection_range (PsppSheetView *tree_view,
- int start_node,
- int end_node,
- gboolean select,
- gboolean skip_start,
- gboolean skip_end)
-{
- if (start_node == end_node)
- return;
-
- /* We skip the first node and jump inside the loop */
- if (skip_start)
- goto skip_first;
-
- do
- {
- /* Small optimization by assuming insensitive nodes are never
- * selected.
- */
- if (select)
- {
- if (tree_view->priv->rubber_band_shift)
- pspp_sheet_view_node_select (tree_view, start_node);
- else if (tree_view->priv->rubber_band_ctrl)
- {
- /* Toggle the selection state */
- if (pspp_sheet_view_node_is_selected (tree_view, start_node))
- pspp_sheet_view_node_unselect (tree_view, start_node);
- else
- pspp_sheet_view_node_select (tree_view, start_node);
- }
- else
- pspp_sheet_view_node_select (tree_view, start_node);
- }
- else
- {
- /* Mirror the above */
- if (tree_view->priv->rubber_band_shift)
- pspp_sheet_view_node_unselect (tree_view, start_node);
- else if (tree_view->priv->rubber_band_ctrl)
- {
- /* Toggle the selection state */
- if (pspp_sheet_view_node_is_selected (tree_view, start_node))
- pspp_sheet_view_node_unselect (tree_view, start_node);
- else
- pspp_sheet_view_node_select (tree_view, start_node);
- }
- else
- pspp_sheet_view_node_unselect (tree_view, start_node);
- }
-
- _pspp_sheet_view_queue_draw_node (tree_view, start_node, NULL);
-
- if (start_node == end_node)
- break;
-
-skip_first:
-
- start_node = pspp_sheet_view_node_next (tree_view, start_node);
-
- if (start_node < 0)
- /* Ran out of tree */
- break;
-
- if (skip_end && start_node == end_node)
- break;
- }
- while (TRUE);
-}
-
-static gint
-pspp_sheet_view_node_find_offset (PsppSheetView *tree_view,
- int node)
-{
- return node * tree_view->priv->fixed_height;
-}
-
-static gint
-pspp_sheet_view_find_offset (PsppSheetView *tree_view,
- gint height,
- int *new_node)
-{
- int fixed_height = tree_view->priv->fixed_height;
- if (fixed_height <= 0
- || height < 0
- || height >= tree_view->priv->row_count * fixed_height)
- {
- *new_node = -1;
- return 0;
- }
- else
- {
- *new_node = height / fixed_height;
- return height % fixed_height;
- }
-}
-
-static void
-pspp_sheet_view_update_rubber_band_selection (PsppSheetView *tree_view)
-{
- int start_node;
- int end_node;
-
- pspp_sheet_view_find_offset (tree_view, MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &start_node);
- pspp_sheet_view_find_offset (tree_view, MAX (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &end_node);
-
- /* Handle the start area first */
- if (tree_view->priv->rubber_band_start_node < 0)
- {
- pspp_sheet_view_update_rubber_band_selection_range (tree_view,
- start_node,
- end_node,
- TRUE,
- FALSE,
- FALSE);
- }
- else if (start_node < tree_view->priv->rubber_band_start_node)
- {
- /* New node is above the old one; selection became bigger */
- pspp_sheet_view_update_rubber_band_selection_range (tree_view,
- start_node,
- tree_view->priv->rubber_band_start_node,
- TRUE,
- FALSE,
- TRUE);
- }
- else if (start_node > tree_view->priv->rubber_band_start_node)
- {
- /* New node is below the old one; selection became smaller */
- pspp_sheet_view_update_rubber_band_selection_range (tree_view,
- tree_view->priv->rubber_band_start_node,
- start_node,
- FALSE,
- FALSE,
- TRUE);
- }
-
- tree_view->priv->rubber_band_start_node = start_node;
-
- /* Next, handle the end area */
- if (tree_view->priv->rubber_band_end_node < 0)
- {
- /* In the event this happens, start_node was also -1; this case is
- * handled above.
- */
- }
- else if (end_node < 0)
- {
- /* Find the last node in the tree */
- pspp_sheet_view_find_offset (tree_view, tree_view->priv->height - 1,
- &end_node);
-
- /* Selection reached end of the tree */
- pspp_sheet_view_update_rubber_band_selection_range (tree_view,
- tree_view->priv->rubber_band_end_node,
- end_node,
- TRUE,
- TRUE,
- FALSE);
- }
- else if (end_node > tree_view->priv->rubber_band_end_node)
- {
- /* New node is below the old one; selection became bigger */
- pspp_sheet_view_update_rubber_band_selection_range (tree_view,
- tree_view->priv->rubber_band_end_node,
- end_node,
- TRUE,
- TRUE,
- FALSE);
- }
- else if (end_node < tree_view->priv->rubber_band_end_node)
- {
- /* New node is above the old one; selection became smaller */
- pspp_sheet_view_update_rubber_band_selection_range (tree_view,
- end_node,
- tree_view->priv->rubber_band_end_node,
- FALSE,
- TRUE,
- FALSE);
- }
-
- tree_view->priv->rubber_band_end_node = end_node;
-}
-
-#define GDK_RECTANGLE_PTR(X) ((GdkRectangle *)(X))
-
-static void
-pspp_sheet_view_update_rubber_band (PsppSheetView *tree_view)
-{
- gint x, y;
- cairo_rectangle_int_t old_area;
- cairo_rectangle_int_t new_area;
- cairo_rectangle_int_t common;
- cairo_region_t *invalid_region;
- PsppSheetViewColumn *column;
-
- old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
- old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
- old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
- old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
-
- gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
-
- x = MAX (x, 0);
- y = MAX (y, 0) + tree_view->priv->dy;
-
- new_area.x = MIN (tree_view->priv->press_start_x, x);
- new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
- new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
- new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
-
- invalid_region = cairo_region_create_rectangle (&old_area);
- cairo_region_union_rectangle (invalid_region, &new_area);
-
- gdk_rectangle_intersect (GDK_RECTANGLE_PTR (&old_area),
- GDK_RECTANGLE_PTR (&new_area), GDK_RECTANGLE_PTR (&common));
- if (common.width > 2 && common.height > 2)
- {
- cairo_region_t *common_region;
-
- /* make sure the border is invalidated */
- common.x += 1;
- common.y += 1;
- common.width -= 2;
- common.height -= 2;
-
- common_region = cairo_region_create_rectangle (&common);
-
- cairo_region_subtract (invalid_region, common_region);
- cairo_region_destroy (common_region);
- }
-
-#if GTK_MAJOR_VERSION == 3
- gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
-#else
- {
- cairo_rectangle_int_t extents;
- GdkRegion *ereg;
- cairo_region_get_extents (invalid_region, &extents);
- ereg = gdk_region_rectangle (GDK_RECTANGLE_PTR (&extents));
- gdk_window_invalidate_region (tree_view->priv->bin_window, ereg, TRUE);
- gdk_region_destroy (ereg);
- }
-#endif
-
- cairo_region_destroy (invalid_region);
-
- tree_view->priv->rubber_band_x = x;
- tree_view->priv->rubber_band_y = y;
- pspp_sheet_view_get_path_at_pos (tree_view, x, y, NULL, &column, NULL, NULL);
-
- pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection);
- pspp_sheet_selection_select_column_range (tree_view->priv->selection,
- tree_view->priv->anchor_column,
- column);
-
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-
- pspp_sheet_view_update_rubber_band_selection (tree_view);
-}
-
-
-
-static gboolean
-pspp_sheet_view_motion_bin_window (GtkWidget *widget,
- GdkEventMotion *event)
-{
- PsppSheetView *tree_view;
- int node;
- gint new_y;
-
- tree_view = (PsppSheetView *) widget;
-
- if (tree_view->priv->row_count == 0)
- return FALSE;
-
- if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
- {
- GdkRectangle background_area, cell_area;
- PsppSheetViewColumn *column;
-
- if (find_click (tree_view, event->x, event->y, &node, &column,
- &background_area, &cell_area)
- && tree_view->priv->focus_column == column
- && tree_view->priv->press_start_node == node)
- return FALSE;
-
- gtk_grab_add (GTK_WIDGET (tree_view));
- pspp_sheet_view_update_rubber_band (tree_view);
-
- tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
- }
- else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
- {
- pspp_sheet_view_update_rubber_band (tree_view);
-
- add_scroll_timeout (tree_view);
- }
-
- /* only check for an initiated drag when a button is pressed */
- if (tree_view->priv->pressed_button >= 0
- && !tree_view->priv->rubber_band_status)
- pspp_sheet_view_maybe_begin_dragging_row (tree_view, event);
-
- new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
- if (new_y < 0)
- new_y = 0;
-
- pspp_sheet_view_find_offset (tree_view, new_y, &node);
-
- tree_view->priv->event_last_x = event->x;
- tree_view->priv->event_last_y = event->y;
-
- prelight_or_select (tree_view, node, event->x, event->y);
-
- return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_motion (GtkWidget *widget,
- GdkEventMotion *event)
-{
- PsppSheetView *tree_view;
-
- tree_view = (PsppSheetView *) widget;
-
- /* Resizing a column */
- if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_RESIZE))
- return pspp_sheet_view_motion_resize_column (widget, event);
-
- /* Drag column */
- if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_DRAG))
- return pspp_sheet_view_motion_drag_column (widget, event);
-
- /* Sanity check it */
- if (event->window == tree_view->priv->bin_window)
- return pspp_sheet_view_motion_bin_window (widget, event);
-
- return FALSE;
-}
-
-/* Invalidate the focus rectangle near the edge of the bin_window; used when
- * the tree is empty.
- */
-static void
-invalidate_empty_focus (PsppSheetView *tree_view)
-{
- GdkRectangle area;
-
- if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
- return;
-
- area.x = 0;
- area.y = 0;
- area.width = gdk_window_get_width (tree_view->priv->bin_window);
- area.height = gdk_window_get_height (tree_view->priv->bin_window);
- gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
-}
-
-/* Draws a focus rectangle near the edge of the bin_window; used when the tree
- * is empty.
- */
-static void
-draw_empty_focus (PsppSheetView *tree_view)
-{
- GtkWidget *widget = GTK_WIDGET (tree_view);
- gint w, h;
- cairo_t *cr = gdk_cairo_create (tree_view->priv->bin_window);
-
- if (!gtk_widget_has_focus (widget))
- return;
-
- w = gdk_window_get_width (tree_view->priv->bin_window);
- h = gdk_window_get_height (tree_view->priv->bin_window);
-
- w -= 2;
- h -= 2;
-
- if (w > 0 && h > 0)
- gtk_paint_focus (gtk_widget_get_style (widget),
- cr,
- gtk_widget_get_state (widget),
- widget,
- NULL,
- 1, 1, w, h);
- cairo_destroy (cr);
-}
-
-static void
-pspp_sheet_view_draw_vertical_grid_lines (PsppSheetView *tree_view,
- cairo_t *cr,
- gint n_visible_columns,
- gint min_y,
- gint max_y)
-{
- GList *list = tree_view->priv->columns;
- gint x = 0;
-
- if (tree_view->priv->grid_lines != PSPP_SHEET_VIEW_GRID_LINES_VERTICAL
- && tree_view->priv->grid_lines != PSPP_SHEET_VIEW_GRID_LINES_BOTH)
- return;
-
- /* Only draw the lines for visible rows and columns */
- gboolean rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
- for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
- list;
- list = (rtl ? list->prev : list->next))
- {
- PsppSheetViewColumn *column = list->data;
-
- if (! column->visible)
- continue;
-
- if (!rtl)
- x += column->width;
-
- cairo_set_line_width (cr, 1.0);
- cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
- cairo_move_to (cr, x + 0.5, min_y);
- cairo_line_to (cr, x + 0.5, max_y - min_y - 0.5);
- cairo_stroke (cr);
-
- if (rtl)
- x += column->width;
- }
-}
-
-/* Warning: Very scary function.
- * Modify at your own risk
- *
- * KEEP IN SYNC WITH pspp_sheet_view_create_row_drag_icon()!
- * FIXME: It's not...
- */
-static void
-pspp_sheet_view_draw_bin (GtkWidget *widget,
- cairo_t *cr)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
- GtkTreePath *path;
- GList *list;
- int node;
- int cursor = -1;
- int drag_highlight = -1;
- GtkTreeIter iter;
- gint new_y;
- gint y_offset, cell_offset;
- gint max_height;
- GdkRectangle background_area;
- GdkRectangle cell_area;
- guint flags;
- gint bin_window_width;
- gint bin_window_height;
- GtkTreePath *cursor_path;
- GtkTreePath *drag_dest_path;
- GList *first_column, *last_column;
- gint vertical_separator;
- gint horizontal_separator;
- gint focus_line_width;
- gboolean allow_rules;
- gboolean rtl;
- gint n_visible_columns;
- gint grid_line_width;
- gboolean row_ending_details;
- gboolean draw_vgrid_lines, draw_hgrid_lines;
- gint min_y, max_y;
- GtkStyleContext *context;
- context = gtk_widget_get_style_context (widget);
-
- GdkRectangle Zarea;
- GtkAllocation allocation;
- gtk_widget_get_allocation (widget, &allocation);
-
- GdkRectangle exposed_rect;
- gdk_cairo_get_clip_rectangle (cr, &exposed_rect);
-
- Zarea.x = 0;
- Zarea.y = 0;
- Zarea.height = allocation.height;
-
- rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
-
- gtk_widget_style_get (widget,
- "horizontal-separator", &horizontal_separator,
- "vertical-separator", &vertical_separator,
- "allow-rules", &allow_rules,
- "focus-line-width", &focus_line_width,
- "row-ending-details", &row_ending_details,
- NULL);
-
- if (tree_view->priv->row_count == 0)
- {
- draw_empty_focus (tree_view);
- return;
- }
-
- validate_visible_area (tree_view);
-
- new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, Zarea.y);
-
- if (new_y < 0)
- new_y = 0;
- y_offset = -pspp_sheet_view_find_offset (tree_view, new_y, &node);
- bin_window_width =
- gdk_window_get_width (tree_view->priv->bin_window);
-
- bin_window_height =
- gdk_window_get_height (tree_view->priv->bin_window);
-
-
- if (tree_view->priv->height < bin_window_height)
- {
- gtk_paint_flat_box (gtk_widget_get_style (widget),
- cr,
- gtk_widget_get_state (widget),
- GTK_SHADOW_NONE,
- widget,
- "cell_even",
- 0, tree_view->priv->height,
- bin_window_width,
- bin_window_height - tree_view->priv->height);
- }
-
- if (node < 0)
- return;
-
- /* find the path for the node */
- path = _pspp_sheet_view_find_path ((PsppSheetView *)widget, node);
- gtk_tree_model_get_iter (tree_view->priv->model,
- &iter,
- path);
- gtk_tree_path_free (path);
-
- cursor_path = NULL;
- drag_dest_path = NULL;
-
- if (tree_view->priv->cursor)
- cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-
- if (cursor_path)
- _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor);
-
- if (tree_view->priv->drag_dest_row)
- drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
-
- if (drag_dest_path)
- _pspp_sheet_view_find_node (tree_view, drag_dest_path,
- &drag_highlight);
-
- draw_vgrid_lines =
- tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_VERTICAL
- || tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_BOTH;
- draw_hgrid_lines =
- tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_HORIZONTAL
- || tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_BOTH;
-
- if (draw_vgrid_lines || draw_hgrid_lines)
- gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
-
- n_visible_columns = 0;
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- if (! PSPP_SHEET_VIEW_COLUMN (list->data)->visible)
- continue;
- n_visible_columns ++;
- }
-
- /* Find the last column */
- for (last_column = g_list_last (tree_view->priv->columns);
- last_column && !(PSPP_SHEET_VIEW_COLUMN (last_column->data)->visible);
- last_column = last_column->prev)
- ;
-
- /* and the first */
- for (first_column = g_list_first (tree_view->priv->columns);
- first_column && !(PSPP_SHEET_VIEW_COLUMN (first_column->data)->visible);
- first_column = first_column->next)
- ;
-
- /* Actually process the expose event. To do this, we want to
- * start at the first node of the event, and walk the tree in
- * order, drawing each successive node.
- */
-
- min_y = y_offset;
- do
- {
- gboolean parity;
- gboolean is_first = FALSE;
- gboolean is_last = FALSE;
- gboolean done = FALSE;
- gboolean selected;
-
- max_height = ROW_HEIGHT (tree_view);
-
- cell_offset = 0;
-
- background_area.y = y_offset + Zarea.y;
- background_area.height = max_height;
- max_y = background_area.y + max_height;
-
- flags = 0;
-
- if (node == tree_view->priv->prelight_node)
- flags |= GTK_CELL_RENDERER_PRELIT;
-
- selected = pspp_sheet_view_node_is_selected (tree_view, node);
-
- parity = node % 2;
-
- for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
- list;
- list = (rtl ? list->prev : list->next))
- {
- PsppSheetViewColumn *column = list->data;
- const gchar *detail = NULL;
- gboolean selected_column;
- GtkStateType state;
-
- if (!column->visible)
- continue;
-
- if (tree_view->priv->selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
- selected_column = column->selected && column->selectable;
- else
- selected_column = TRUE;
-
- if (selected && selected_column)
- flags |= GTK_CELL_RENDERER_SELECTED;
- else
- flags &= ~GTK_CELL_RENDERER_SELECTED;
-
- if (column->show_sort_indicator)
- flags |= GTK_CELL_RENDERER_SORTED;
- else
- flags &= ~GTK_CELL_RENDERER_SORTED;
-
- if (cursor == node)
- flags |= GTK_CELL_RENDERER_FOCUSED;
- else
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
-
- background_area.x = cell_offset;
- background_area.width = column->width;
-
- cell_area = background_area;
- cell_area.y += vertical_separator / 2;
- cell_area.x += horizontal_separator / 2;
- cell_area.height -= vertical_separator;
- cell_area.width -= horizontal_separator;
-
- if (draw_vgrid_lines)
- {
- if (list == first_column)
- {
- cell_area.width -= grid_line_width / 2;
- }
- else if (list == last_column)
- {
- cell_area.x += grid_line_width / 2;
- cell_area.width -= grid_line_width / 2;
- }
- else
- {
- cell_area.x += grid_line_width / 2;
- cell_area.width -= grid_line_width;
- }
- }
-
- if (draw_hgrid_lines)
- {
- cell_area.y += grid_line_width / 2;
- cell_area.height -= grid_line_width;
- }
-
- if (!gdk_rectangle_intersect (&background_area, &exposed_rect, NULL))
- {
- cell_offset += column->width;
- continue;
- }
-
-
- pspp_sheet_view_column_cell_set_cell_data (column,
- tree_view->priv->model,
- &iter);
-
- /* Select the detail for drawing the cell. relevant
- * factors are parity, sortedness, and whether to
- * display rules.
- */
- if (allow_rules && tree_view->priv->has_rules)
- {
- if ((flags & GTK_CELL_RENDERER_SORTED) &&
- n_visible_columns >= 3)
- {
- if (parity)
- detail = "cell_odd_ruled_sorted";
- else
- detail = "cell_even_ruled_sorted";
- }
- else
- {
- if (parity)
- detail = "cell_odd_ruled";
- else
- detail = "cell_even_ruled";
- }
- }
- else
- {
- if ((flags & GTK_CELL_RENDERER_SORTED) &&
- n_visible_columns >= 3)
- {
- if (parity)
- detail = "cell_odd_sorted";
- else
- detail = "cell_even_sorted";
- }
- else
- {
- if (parity)
- detail = "cell_odd";
- else
- detail = "cell_even";
- }
- }
-
- g_assert (detail);
-
- gtk_style_context_save (context);
- state = gtk_cell_renderer_get_state (NULL, widget, flags);
- gtk_style_context_set_state (context, state);
- gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
-
- /* Draw background */
- gtk_render_background (context, cr,
- background_area.x,
- background_area.y,
- background_area.width,
- background_area.height);
-
- /* Draw frame */
- gtk_render_frame (context, cr,
- background_area.x,
- background_area.y,
- background_area.width,
- background_area.height);
-
- if (draw_hgrid_lines)
- {
- cairo_set_line_width (cr, 1.0);
- cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
-
- if (background_area.y >= 0)
- {
- cairo_move_to (cr, background_area.x, background_area.y - 0.5);
- cairo_line_to (cr, background_area.x + background_area.width,
- background_area.y - 0.5);
- }
-
- if (y_offset + max_height <= Zarea.height - 0.5)
- {
- cairo_move_to (cr, background_area.x, background_area.y + max_height - 0.5);
- cairo_line_to (cr, background_area.x + background_area.width,
- background_area.y + max_height - 0.5);
- }
- cairo_stroke (cr);
- }
-
- _pspp_sheet_view_column_cell_render (column,
- cr,
- &background_area,
- &cell_area,
- flags);
-
-
- cell_offset += column->width;
- gtk_style_context_restore (context);
- }
-
- if (node == drag_highlight)
- {
- /* Draw indicator for the drop
- */
- gint highlight_y = -1;
- int node = -1;
- gint width;
-
- switch (tree_view->priv->drag_dest_pos)
- {
- case PSPP_SHEET_VIEW_DROP_BEFORE:
- highlight_y = background_area.y - 1;
- if (highlight_y < 0)
- highlight_y = 0;
- break;
-
- case PSPP_SHEET_VIEW_DROP_AFTER:
- highlight_y = background_area.y + background_area.height - 1;
- break;
-
- case PSPP_SHEET_VIEW_DROP_INTO_OR_BEFORE:
- case PSPP_SHEET_VIEW_DROP_INTO_OR_AFTER:
- _pspp_sheet_view_find_node (tree_view, drag_dest_path, &node);
-
- if (node < 0)
- break;
- width = gdk_window_get_width (tree_view->priv->bin_window);
-
- if (row_ending_details)
- gtk_paint_focus (gtk_widget_get_style (widget),
- cr,
- gtk_widget_get_state (widget),
- widget,
- (is_first
- ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
- : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
- 0, BACKGROUND_FIRST_PIXEL (tree_view, node)
- - focus_line_width / 2,
- width, ROW_HEIGHT (tree_view)
- - focus_line_width + 1);
- else
- gtk_paint_focus (gtk_widget_get_style (widget),
- cr,
- gtk_widget_get_state (widget),
- widget,
- "treeview-drop-indicator",
- 0, BACKGROUND_FIRST_PIXEL (tree_view, node)
- - focus_line_width / 2,
- width, ROW_HEIGHT (tree_view)
- - focus_line_width + 1);
- break;
- }
-
- }
-
- y_offset += max_height;
-
- do
- {
- node = pspp_sheet_view_node_next (tree_view, node);
- if (node >= 0)
- {
- gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
- done = TRUE;
-
- /* Sanity Check! */
- TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
- }
- else
- goto done;
- }
- while (!done);
- }
- while (y_offset < Zarea.height);
-
-done:
- pspp_sheet_view_draw_vertical_grid_lines (tree_view, cr, n_visible_columns,
- min_y, max_y);
-
- if (cursor_path)
- gtk_tree_path_free (cursor_path);
-
- if (drag_dest_path)
- gtk_tree_path_free (drag_dest_path);
-
- return;
-}
-
-
-static gboolean
-pspp_sheet_view_draw (GtkWidget *widget,
- cairo_t *cr)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
- GtkStyleContext *context;
-
- context = gtk_widget_get_style_context (widget);
-
- if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
- {
- GList *tmp_list;
-
- cairo_save (cr);
- gtk_cairo_transform_to_window(cr,widget,tree_view->priv->bin_window);
- pspp_sheet_view_draw_bin (widget, cr);
- cairo_restore (cr);
-
- /* We can't just chain up to Container::expose as it will try to send the
- * event to the headers, so we handle propagating it to our children
- * (eg. widgets being edited) ourselves.
- */
- tmp_list = tree_view->priv->children;
- while (tmp_list)
- {
- PsppSheetViewChild *child = tmp_list->data;
- tmp_list = tmp_list->next;
-
- gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
- }
- }
- else
- {
- gtk_render_background (context, cr,
- 0, 0,
- gtk_widget_get_allocated_width (widget),
- gtk_widget_get_allocated_height (widget));
- }
-
- gtk_style_context_save (context);
- gtk_style_context_remove_class (context, GTK_STYLE_CLASS_VIEW);
-
- if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
- {
- gint n_visible_columns;
- GList *list;
-
- for (list = tree_view->priv->columns; list != NULL; list = list->next)
- {
- PsppSheetViewColumn *column = list->data;
-
- if (column == tree_view->priv->drag_column || !column->visible)
- continue;
-
- if (span_intersects (column->allocation.x, column->allocation.width,
- (int) gtk_adjustment_get_value (tree_view->priv->hadjustment),
- (int) gtk_widget_get_allocated_width (widget))
- && column->button != NULL)
- gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
- column->button, cr);
- }
-
- n_visible_columns = 0;
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- if (! PSPP_SHEET_VIEW_COLUMN (list->data)->visible)
- continue;
- n_visible_columns ++;
- }
- cairo_save (cr);
- gtk_cairo_transform_to_window(cr,widget,tree_view->priv->header_window);
- pspp_sheet_view_draw_vertical_grid_lines (tree_view,
- cr,
- n_visible_columns,
- 0,
- TREE_VIEW_HEADER_HEIGHT (tree_view));
- cairo_restore (cr);
- }
- if (tree_view->priv->drag_window &&
- gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
- {
- gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
- tree_view->priv->drag_column->button,
- cr);
- }
-
- gtk_style_context_restore (context);
- return FALSE;
-}
-
-enum
-{
- DROP_HOME,
- DROP_RIGHT,
- DROP_LEFT,
- DROP_END
-};
-
-/* returns 0x1 when no column has been found -- yes it's hackish */
-static PsppSheetViewColumn *
-pspp_sheet_view_get_drop_column (PsppSheetView *tree_view,
- PsppSheetViewColumn *column,
- gint drop_position)
-{
- PsppSheetViewColumn *left_column = NULL;
- PsppSheetViewColumn *cur_column = NULL;
- GList *tmp_list;
-
- if (!column->reorderable)
- return (PsppSheetViewColumn *)0x1;
-
- switch (drop_position)
- {
- case DROP_HOME:
- /* find first column where we can drop */
- tmp_list = tree_view->priv->columns;
- if (column == PSPP_SHEET_VIEW_COLUMN (tmp_list->data))
- return (PsppSheetViewColumn *)0x1;
-
- while (tmp_list)
- {
- g_assert (tmp_list);
-
- cur_column = PSPP_SHEET_VIEW_COLUMN (tmp_list->data);
- tmp_list = tmp_list->next;
-
- if (left_column && left_column->visible == FALSE)
- continue;
-
- if (!tree_view->priv->column_drop_func)
- return left_column;
-
- if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
- {
- left_column = cur_column;
- continue;
- }
-
- return left_column;
- }
-
- if (!tree_view->priv->column_drop_func)
- return left_column;
-
- if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
- return left_column;
- else
- return (PsppSheetViewColumn *)0x1;
- break;
-
- case DROP_RIGHT:
- /* find first column after column where we can drop */
- tmp_list = tree_view->priv->columns;
-
- for (; tmp_list; tmp_list = tmp_list->next)
- if (PSPP_SHEET_VIEW_COLUMN (tmp_list->data) == column)
- break;
-
- if (!tmp_list || !tmp_list->next)
- return (PsppSheetViewColumn *)0x1;
-
- tmp_list = tmp_list->next;
- left_column = PSPP_SHEET_VIEW_COLUMN (tmp_list->data);
- tmp_list = tmp_list->next;
-
- while (tmp_list)
- {
- g_assert (tmp_list);
-
- cur_column = PSPP_SHEET_VIEW_COLUMN (tmp_list->data);
- tmp_list = tmp_list->next;
-
- if (left_column && left_column->visible == FALSE)
- {
- left_column = cur_column;
- if (tmp_list)
- tmp_list = tmp_list->next;
- continue;
- }
-
- if (!tree_view->priv->column_drop_func)
- return left_column;
-
- if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
- {
- left_column = cur_column;
- continue;
- }
-
- return left_column;
- }
-
- if (!tree_view->priv->column_drop_func)
- return left_column;
-
- if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
- return left_column;
- else
- return (PsppSheetViewColumn *)0x1;
- break;
-
- case DROP_LEFT:
- /* find first column before column where we can drop */
- tmp_list = tree_view->priv->columns;
-
- for (; tmp_list; tmp_list = tmp_list->next)
- if (PSPP_SHEET_VIEW_COLUMN (tmp_list->data) == column)
- break;
-
- if (!tmp_list || !tmp_list->prev)
- return (PsppSheetViewColumn *)0x1;
-
- tmp_list = tmp_list->prev;
- cur_column = PSPP_SHEET_VIEW_COLUMN (tmp_list->data);
- tmp_list = tmp_list->prev;
-
- while (tmp_list)
- {
- g_assert (tmp_list);
-
- left_column = PSPP_SHEET_VIEW_COLUMN (tmp_list->data);
-
- if (left_column && !left_column->visible)
- {
- /*if (!tmp_list->prev)
- return (PsppSheetViewColumn *)0x1;
- */
-/*
- cur_column = PSPP_SHEET_VIEW_COLUMN (tmp_list->prev->data);
- tmp_list = tmp_list->prev->prev;
- continue;*/
-
- cur_column = left_column;
- if (tmp_list)
- tmp_list = tmp_list->prev;
- continue;
- }
-
- if (!tree_view->priv->column_drop_func)
- return left_column;
-
- if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
- return left_column;
-
- cur_column = left_column;
- tmp_list = tmp_list->prev;
- }
-
- if (!tree_view->priv->column_drop_func)
- return NULL;
-
- if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
- return NULL;
- else
- return (PsppSheetViewColumn *)0x1;
- break;
-
- case DROP_END:
- /* same as DROP_HOME case, but doing it backwards */
- tmp_list = g_list_last (tree_view->priv->columns);
- cur_column = NULL;
-
- if (column == PSPP_SHEET_VIEW_COLUMN (tmp_list->data))
- return (PsppSheetViewColumn *)0x1;
-
- while (tmp_list)
- {
- g_assert (tmp_list);
-
- left_column = PSPP_SHEET_VIEW_COLUMN (tmp_list->data);
-
- if (left_column && !left_column->visible)
- {
- cur_column = left_column;
- tmp_list = tmp_list->prev;
- }
-
- if (!tree_view->priv->column_drop_func)
- return left_column;
-
- if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
- return left_column;
-
- cur_column = left_column;
- tmp_list = tmp_list->prev;
- }
-
- if (!tree_view->priv->column_drop_func)
- return NULL;
-
- if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
- return NULL;
- else
- return (PsppSheetViewColumn *)0x1;
- break;
- }
-
- return (PsppSheetViewColumn *)0x1;
-}
-
-static gboolean
-pspp_sheet_view_key_press (GtkWidget *widget,
- GdkEventKey *event)
-{
- PsppSheetView *tree_view = (PsppSheetView *) widget;
-
- if (tree_view->priv->rubber_band_status)
- {
- if (event->keyval == GDK_Escape)
- pspp_sheet_view_stop_rubber_band (tree_view);
-
- return TRUE;
- }
-
- if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_DRAG))
- {
- if (event->keyval == GDK_Escape)
- {
- tree_view->priv->cur_reorder = NULL;
- pspp_sheet_view_button_release_drag_column (widget, NULL);
- }
- return TRUE;
- }
-
- if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_HEADERS_VISIBLE))
- {
- GList *focus_column;
- gboolean rtl;
-
- rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
- for (focus_column = tree_view->priv->columns;
- focus_column;
- focus_column = focus_column->next)
- {
- PsppSheetViewColumn *column = PSPP_SHEET_VIEW_COLUMN (focus_column->data);
-
- if (column->button && gtk_widget_has_focus (column->button))
- break;
- }
-
- if (focus_column &&
- (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
- (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
- || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
- {
- PsppSheetViewColumn *column = PSPP_SHEET_VIEW_COLUMN (focus_column->data);
-
- if (!column->resizable)
- {
- gtk_widget_error_bell (widget);
- return TRUE;
- }
-
- if (event->keyval == (rtl ? GDK_Right : GDK_Left)
- || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
- {
- gint old_width = column->resized_width;
-
- column->resized_width = MAX (column->resized_width,
- column->width);
- column->resized_width -= 2;
- if (column->resized_width < 0)
- column->resized_width = 0;
-
- if (column->min_width == -1)
- column->resized_width = MAX (column->button_request,
- column->resized_width);
- else
- column->resized_width = MAX (column->min_width,
- column->resized_width);
-
- if (column->max_width != -1)
- column->resized_width = MIN (column->resized_width,
- column->max_width);
-
- column->use_resized_width = TRUE;
-
- if (column->resized_width != old_width)
- gtk_widget_queue_resize (widget);
- else
- gtk_widget_error_bell (widget);
- }
- else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
- || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
- {
- gint old_width = column->resized_width;
-
- column->resized_width = MAX (column->resized_width,
- column->width);
- column->resized_width += 2;
-
- if (column->max_width != -1)
- column->resized_width = MIN (column->resized_width,
- column->max_width);
-
- column->use_resized_width = TRUE;
-
- if (column->resized_width != old_width)
- gtk_widget_queue_resize (widget);
- else
- gtk_widget_error_bell (widget);
- }
-
- return TRUE;
- }
-
- if (focus_column &&
- (event->state & GDK_MOD1_MASK) &&
- (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
- || event->keyval == GDK_Right || event->keyval == GDK_KP_Right
- || event->keyval == GDK_Home || event->keyval == GDK_KP_Home
- || event->keyval == GDK_End || event->keyval == GDK_KP_End))
- {
- PsppSheetViewColumn *column = PSPP_SHEET_VIEW_COLUMN (focus_column->data);
-
- if (event->keyval == (rtl ? GDK_Right : GDK_Left)
- || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
- {
- PsppSheetViewColumn *col;
- col = pspp_sheet_view_get_drop_column (tree_view, column, DROP_LEFT);
- if (col != (PsppSheetViewColumn *)0x1)
- pspp_sheet_view_move_column_after (tree_view, column, col);
- else
- gtk_widget_error_bell (widget);
- }
- else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
- || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
- {
- PsppSheetViewColumn *col;
- col = pspp_sheet_view_get_drop_column (tree_view, column, DROP_RIGHT);
- if (col != (PsppSheetViewColumn *)0x1)
- pspp_sheet_view_move_column_after (tree_view, column, col);
- else
- gtk_widget_error_bell (widget);
- }
- else if (event->keyval == GDK_Home || event->keyval == GDK_KP_Home)
- {
- PsppSheetViewColumn *col;
- col = pspp_sheet_view_get_drop_column (tree_view, column, DROP_HOME);
- if (col != (PsppSheetViewColumn *)0x1)
- pspp_sheet_view_move_column_after (tree_view, column, col);
- else
- gtk_widget_error_bell (widget);
- }
- else if (event->keyval == GDK_End || event->keyval == GDK_KP_End)
- {
- PsppSheetViewColumn *col;
- col = pspp_sheet_view_get_drop_column (tree_view, column, DROP_END);
- if (col != (PsppSheetViewColumn *)0x1)
- pspp_sheet_view_move_column_after (tree_view, column, col);
- else
- gtk_widget_error_bell (widget);
- }
-
- return TRUE;
- }
- }
-
- /* Chain up to the parent class. It handles the keybindings. */
- if (GTK_WIDGET_CLASS (pspp_sheet_view_parent_class)->key_press_event (widget, event))
- return TRUE;
-
- if (tree_view->priv->search_entry_avoid_unhandled_binding)
- {
- tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
- return FALSE;
- }
-
- /* We pass the event to the search_entry. If its text changes, then we start
- * the typeahead find capabilities. */
- if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
- && tree_view->priv->enable_search
- && !tree_view->priv->search_custom_entry_set)
- {
- GdkEvent *new_event;
- char *old_text;
- const char *new_text;
- gboolean retval;
- GdkScreen *screen;
- gboolean text_modified;
- gulong popup_menu_id;
-
- pspp_sheet_view_ensure_interactive_directory (tree_view);
-
- /* Make a copy of the current text */
- old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
- new_event = gdk_event_copy ((GdkEvent *) event);
- g_object_unref (((GdkEventKey *) new_event)->window);
- ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
- gtk_widget_realize (tree_view->priv->search_window);
-
- popup_menu_id = g_signal_connect (tree_view->priv->search_entry,
- "popup-menu", G_CALLBACK (gtk_true),
- NULL);
-
- /* Move the entry off screen */
- screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
- gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
- gdk_screen_get_width (screen) + 1,
- gdk_screen_get_height (screen) + 1);
- gtk_widget_show (tree_view->priv->search_window);
-
- /* Send the event to the window. If the preedit_changed signal is emitted
- * during this event, we will set priv->imcontext_changed */
- tree_view->priv->imcontext_changed = FALSE;
- retval = gtk_widget_event (tree_view->priv->search_window, new_event);
- gdk_event_free (new_event);
- gtk_widget_hide (tree_view->priv->search_window);
-
- g_signal_handler_disconnect (tree_view->priv->search_entry,
- popup_menu_id);
-
- /* We check to make sure that the entry tried to handle the text, and that
- * the text has changed.
- */
- new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
- text_modified = strcmp (old_text, new_text) != 0;
- g_free (old_text);
- if (tree_view->priv->imcontext_changed || /* we're in a preedit */
- (retval && text_modified)) /* ...or the text was modified */
- {
- if (pspp_sheet_view_real_start_interactive_search (tree_view, FALSE))
- {
- gtk_widget_grab_focus (GTK_WIDGET (tree_view));
- return TRUE;
- }
- else
- {
- gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
- return FALSE;
- }
- }
- }
-
- return FALSE;
-}
-
-static gboolean
-pspp_sheet_view_key_release (GtkWidget *widget,
- GdkEventKey *event)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-
- if (tree_view->priv->rubber_band_status)
- return TRUE;
-
- return GTK_WIDGET_CLASS (pspp_sheet_view_parent_class)->key_release_event (widget, event);
-}
-
-/* FIXME Is this function necessary? Can I get an enter_notify event
- * w/o either an expose event or a mouse motion event?
- */
-static gboolean
-pspp_sheet_view_enter_notify (GtkWidget *widget,
- GdkEventCrossing *event)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
- int node;
- gint new_y;
-
- /* Sanity check it */
- if (event->window != tree_view->priv->bin_window)
- return FALSE;
-
- if (tree_view->priv->row_count == 0)
- return FALSE;
-
- if (event->mode == GDK_CROSSING_GRAB ||
- event->mode == GDK_CROSSING_GTK_GRAB ||
- event->mode == GDK_CROSSING_GTK_UNGRAB ||
- event->mode == GDK_CROSSING_STATE_CHANGED)
- return TRUE;
-
- /* find the node internally */
- new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
- if (new_y < 0)
- new_y = 0;
- pspp_sheet_view_find_offset (tree_view, new_y, &node);
-
- tree_view->priv->event_last_x = event->x;
- tree_view->priv->event_last_y = event->y;
-
- prelight_or_select (tree_view, node, event->x, event->y);
-
- return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_leave_notify (GtkWidget *widget,
- GdkEventCrossing *event)
-{
- PsppSheetView *tree_view;
-
- if (event->mode == GDK_CROSSING_GRAB)
- return TRUE;
-
- tree_view = PSPP_SHEET_VIEW (widget);
-
- if (tree_view->priv->prelight_node >= 0)
- _pspp_sheet_view_queue_draw_node (tree_view,
- tree_view->priv->prelight_node,
- NULL);
-
- tree_view->priv->event_last_x = -10000;
- tree_view->priv->event_last_y = -10000;
-
- prelight_or_select (tree_view,
- -1,
- -1000, -1000); /* coords not possibly over an arrow */
-
- return TRUE;
-}
-
-
-static gint
-pspp_sheet_view_focus_out (GtkWidget *widget,
- GdkEventFocus *event)
-{
- PsppSheetView *tree_view;
-
- tree_view = PSPP_SHEET_VIEW (widget);
-
- gtk_widget_queue_draw (widget);
-
- /* destroy interactive search dialog */
- if (tree_view->priv->search_window)
- pspp_sheet_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
-
- return FALSE;
-}
-
-
-/* Incremental Reflow
- */
-
-static void
-pspp_sheet_view_node_queue_redraw (PsppSheetView *tree_view,
- int node)
-{
- GtkAllocation allocation;
- gint y = pspp_sheet_view_node_find_offset (tree_view, node)
- - gtk_adjustment_get_value (tree_view->priv->vadjustment)
- + TREE_VIEW_HEADER_HEIGHT (tree_view);
-
- gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
-
- gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
- 0, y,
- allocation.width,
- tree_view->priv->fixed_height);
-}
-
-static gboolean
-node_is_visible (PsppSheetView *tree_view,
- int node)
-{
- int y;
- int height;
-
- y = pspp_sheet_view_node_find_offset (tree_view, node);
- height = ROW_HEIGHT (tree_view);
-
- if (y >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
- y + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
- + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
- return TRUE;
-
- return FALSE;
-}
-
-/* Returns the row height. */
-static gint
-validate_row (PsppSheetView *tree_view,
- int node,
- GtkTreeIter *iter,
- GtkTreePath *path)
-{
- PsppSheetViewColumn *column;
- GList *list, *first_column, *last_column;
- gint height = 0;
- gint horizontal_separator;
- gint vertical_separator;
- gint focus_line_width;
- gboolean draw_vgrid_lines, draw_hgrid_lines;
- gint focus_pad;
- gint grid_line_width;
- gboolean wide_separators;
- gint separator_height;
-
- gtk_widget_style_get (GTK_WIDGET (tree_view),
- "focus-padding", &focus_pad,
- "focus-line-width", &focus_line_width,
- "horizontal-separator", &horizontal_separator,
- "vertical-separator", &vertical_separator,
- "grid-line-width", &grid_line_width,
- "wide-separators", &wide_separators,
- "separator-height", &separator_height,
- NULL);
-
- draw_vgrid_lines =
- tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_VERTICAL
- || tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_BOTH;
- draw_hgrid_lines =
- tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_HORIZONTAL
- || tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_BOTH;
-
- for (last_column = g_list_last (tree_view->priv->columns);
- last_column && !(PSPP_SHEET_VIEW_COLUMN (last_column->data)->visible);
- last_column = last_column->prev)
- ;
-
- for (first_column = g_list_first (tree_view->priv->columns);
- first_column && !(PSPP_SHEET_VIEW_COLUMN (first_column->data)->visible);
- first_column = first_column->next)
- ;
-
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- gint tmp_width;
- gint tmp_height;
-
- column = list->data;
-
- if (! column->visible)
- continue;
-
- pspp_sheet_view_column_cell_set_cell_data (column, tree_view->priv->model, iter);
- pspp_sheet_view_column_cell_get_size (column,
- NULL, NULL, NULL,
- &tmp_width, &tmp_height);
-
- tmp_height += vertical_separator;
- height = MAX (height, tmp_height);
-
- tmp_width = tmp_width + horizontal_separator;
-
- if (draw_vgrid_lines)
- {
- if (list->data == first_column || list->data == last_column)
- tmp_width += grid_line_width / 2.0;
- else
- tmp_width += grid_line_width;
- }
-
- if (tmp_width > column->requested_width)
- column->requested_width = tmp_width;
- }
-
- if (draw_hgrid_lines)
- height += grid_line_width;
-
- tree_view->priv->post_validation_flag = TRUE;
- return height;
-}
-
-
-static void
-validate_visible_area (PsppSheetView *tree_view)
-{
- GtkTreePath *path = NULL;
- GtkTreePath *above_path = NULL;
- GtkTreeIter iter;
- int node = -1;
- gint total_height;
- gint area_above = 0;
- gint area_below = 0;
- GtkAllocation allocation;
-
- if (tree_view->priv->row_count == 0)
- return;
-
- if (tree_view->priv->scroll_to_path == NULL)
- return;
-
- gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
-
- total_height = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
-
- if (total_height == 0)
- return;
-
- path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
- if (path)
- {
- /* we are going to scroll, and will update dy */
- _pspp_sheet_view_find_node (tree_view, path, &node);
- gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
-
- if (tree_view->priv->scroll_to_use_align)
- {
- gint height = ROW_HEIGHT (tree_view);
- area_above = (total_height - height) *
- tree_view->priv->scroll_to_row_align;
- area_below = total_height - area_above - height;
- area_above = MAX (area_above, 0);
- area_below = MAX (area_below, 0);
- }
- else
- {
- /* two cases:
- * 1) row not visible
- * 2) row visible
- */
- gint dy;
- gint height = ROW_HEIGHT (tree_view);
-
- dy = pspp_sheet_view_node_find_offset (tree_view, node);
-
- if (dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
- dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
- + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
- {
- /* row visible: keep the row at the same position */
- area_above = dy - gtk_adjustment_get_value (tree_view->priv->vadjustment);
- area_below = (gtk_adjustment_get_value (tree_view->priv->vadjustment) +
- gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
- - dy - height;
- }
- else
- {
- /* row not visible */
- if (dy >= 0
- && dy + height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
- {
- /* row at the beginning -- fixed */
- area_above = dy;
- area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment)
- - area_above - height;
- }
- else if (dy >= (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
- gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
- {
- /* row at the end -- fixed */
- area_above = dy - (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
- gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
- area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) -
- area_above - height;
-
- if (area_below < 0)
- {
- area_above = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) - height;
- area_below = 0;
- }
- }
- else
- {
- /* row somewhere in the middle, bring it to the top
- * of the view
- */
- area_above = 0;
- area_below = total_height - height;
- }
- }
- }
- }
- else
- /* the scroll to isn't valid; ignore it.
- */
- {
- gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
- tree_view->priv->scroll_to_path = NULL;
- return;
- }
-
- above_path = gtk_tree_path_copy (path);
-
- /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
- * backwards is much slower then forward, as there is no iter_prev function.
- * We go forwards first in case we run out of tree. Then we go backwards to
- * fill out the top.
- */
- while (node >= 0 && area_below > 0)
- {
- gboolean done = FALSE;
- do
- {
- node = pspp_sheet_view_node_next (tree_view, node);
- if (node >= 0)
- {
- gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
- done = TRUE;
- gtk_tree_path_next (path);
-
- /* Sanity Check! */
- TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
- }
- else
- break;
- }
- while (!done);
-
- if (node < 0)
- break;
-
- area_below -= ROW_HEIGHT (tree_view);
- }
- gtk_tree_path_free (path);
-
- /* If we ran out of tree, and have extra area_below left, we need to add it
- * to area_above */
- if (area_below > 0)
- area_above += area_below;
-
- _pspp_sheet_view_find_node (tree_view, above_path, &node);
-
- /* We walk backwards */
- while (area_above > 0)
- {
- node = pspp_sheet_view_node_prev (tree_view, node);
-
- /* Always find the new path in the tree. We cannot just assume
- * a gtk_tree_path_prev() is enough here, as there might be children
- * in between this node and the previous sibling node. If this
- * appears to be a performance hotspot in profiles, we can look into
- * intrigate logic for keeping path, node and iter in sync like
- * we do for forward walks. (Which will be hard because of the lacking
- * iter_prev).
- */
-
- if (node < 0)
- break;
-
- gtk_tree_path_free (above_path);
- above_path = _pspp_sheet_view_find_path (tree_view, node);
-
- gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
-
- area_above -= ROW_HEIGHT (tree_view);
- }
-
- /* set the dy here to scroll to the path,
- * and sync the top row accordingly
- */
- pspp_sheet_view_set_top_row (tree_view, above_path, -area_above);
- pspp_sheet_view_top_row_to_dy (tree_view);
-
- gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
- tree_view->priv->scroll_to_path = NULL;
-
- if (above_path)
- gtk_tree_path_free (above_path);
-
- if (tree_view->priv->scroll_to_column)
- {
- tree_view->priv->scroll_to_column = NULL;
- }
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-}
-
-static void
-initialize_fixed_height_mode (PsppSheetView *tree_view)
-{
- if (!tree_view->priv->row_count)
- return;
-
- if (tree_view->priv->fixed_height_set)
- return;
-
- if (tree_view->priv->fixed_height < 0)
- {
- GtkTreeIter iter;
- GtkTreePath *path;
-
- int node = 0;
-
- path = _pspp_sheet_view_find_path (tree_view, node);
- gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
-
- tree_view->priv->fixed_height = validate_row (tree_view, node, &iter, path);
-
- gtk_tree_path_free (path);
-
- g_object_notify (G_OBJECT (tree_view), "fixed-height");
- }
-}
-
-/* Our strategy for finding nodes to validate is a little convoluted. We find
- * the left-most uninvalidated node. We then try walking right, validating
- * nodes. Once we find a valid node, we repeat the previous process of finding
- * the first invalid node.
- */
-
-static gboolean
-validate_rows_handler (PsppSheetView *tree_view)
-{
- initialize_fixed_height_mode (tree_view);
- if (tree_view->priv->validate_rows_timer)
- {
- g_source_remove (tree_view->priv->validate_rows_timer);
- tree_view->priv->validate_rows_timer = 0;
- }
-
- return FALSE;
-}
-
-static gboolean
-do_presize_handler (PsppSheetView *tree_view)
-{
- GtkRequisition requisition;
-
- validate_visible_area (tree_view);
- tree_view->priv->presize_handler_timer = 0;
-
- if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
- return FALSE;
-
- gtk_widget_get_preferred_size (GTK_WIDGET (tree_view), NULL, &requisition);
-
- gtk_adjustment_set_upper (tree_view->priv->hadjustment, MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), (gfloat)requisition.width));
- gtk_adjustment_set_upper (tree_view->priv->vadjustment, MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), (gfloat)requisition.height));
- gtk_adjustment_changed (tree_view->priv->hadjustment);
- gtk_adjustment_changed (tree_view->priv->vadjustment);
- gtk_widget_queue_resize (GTK_WIDGET (tree_view));
-
- return FALSE;
-}
-
-static gboolean
-presize_handler_callback (gpointer data)
-{
- do_presize_handler (PSPP_SHEET_VIEW (data));
-
- return FALSE;
-}
-
-static void
-install_presize_handler (PsppSheetView *tree_view)
-{
- if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
- return;
-
- if (! tree_view->priv->presize_handler_timer)
- {
- tree_view->priv->presize_handler_timer =
- gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
- }
- if (! tree_view->priv->validate_rows_timer)
- {
- tree_view->priv->validate_rows_timer =
- gdk_threads_add_idle_full (PSPP_SHEET_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
- }
-}
-
-static gboolean
-scroll_sync_handler (PsppSheetView *tree_view)
-{
- if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
- gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
- else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
- pspp_sheet_view_top_row_to_dy (tree_view);
- else
- pspp_sheet_view_dy_to_top_row (tree_view);
-
- tree_view->priv->scroll_sync_timer = 0;
-
- return FALSE;
-}
-
-static void
-install_scroll_sync_handler (PsppSheetView *tree_view)
-{
- if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
- return;
-
- if (!tree_view->priv->scroll_sync_timer)
- {
- tree_view->priv->scroll_sync_timer =
- gdk_threads_add_idle_full (PSPP_SHEET_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
- }
-}
-
-static void
-pspp_sheet_view_set_top_row (PsppSheetView *tree_view,
- GtkTreePath *path,
- gint offset)
-{
- gtk_tree_row_reference_free (tree_view->priv->top_row);
-
- if (!path)
- {
- tree_view->priv->top_row = NULL;
- tree_view->priv->top_row_dy = 0;
- }
- else
- {
- tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
- tree_view->priv->top_row_dy = offset;
- }
-}
-
-/* Always call this iff dy is in the visible range. If the tree is empty, then
- * it's set to be NULL, and top_row_dy is 0;
- */
-static void
-pspp_sheet_view_dy_to_top_row (PsppSheetView *tree_view)
-{
- gint offset;
- GtkTreePath *path;
- int node;
-
- if (tree_view->priv->row_count == 0)
- {
- pspp_sheet_view_set_top_row (tree_view, NULL, 0);
- }
- else
- {
- offset = pspp_sheet_view_find_offset (tree_view,
- tree_view->priv->dy,
- &node);
-
- if (node < 0)
- {
- pspp_sheet_view_set_top_row (tree_view, NULL, 0);
- }
- else
- {
- path = _pspp_sheet_view_find_path (tree_view, node);
- pspp_sheet_view_set_top_row (tree_view, path, offset);
- gtk_tree_path_free (path);
- }
- }
-}
-
-static void
-pspp_sheet_view_top_row_to_dy (PsppSheetView *tree_view)
-{
- GtkTreePath *path;
- int node;
- int new_dy;
-
- /* Avoid recursive calls */
- if (tree_view->priv->in_top_row_to_dy)
- return;
-
- if (tree_view->priv->top_row)
- path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
- else
- path = NULL;
-
- if (!path)
- node = -1;
- else
- _pspp_sheet_view_find_node (tree_view, path, &node);
-
- if (path)
- gtk_tree_path_free (path);
-
- if (node < 0)
- {
- /* keep dy and set new toprow */
- gtk_tree_row_reference_free (tree_view->priv->top_row);
- tree_view->priv->top_row = NULL;
- tree_view->priv->top_row_dy = 0;
- /* DO NOT install the idle handler */
- pspp_sheet_view_dy_to_top_row (tree_view);
- return;
- }
-
- if (ROW_HEIGHT (tree_view) < tree_view->priv->top_row_dy)
- {
- /* new top row -- do NOT install the idle handler */
- pspp_sheet_view_dy_to_top_row (tree_view);
- return;
- }
-
- new_dy = pspp_sheet_view_node_find_offset (tree_view, node);
- new_dy += tree_view->priv->top_row_dy;
-
- if (new_dy + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
- new_dy = tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
-
- new_dy = MAX (0, new_dy);
-
- tree_view->priv->in_top_row_to_dy = TRUE;
- gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
- tree_view->priv->in_top_row_to_dy = FALSE;
-}
-
-
-void
-_pspp_sheet_view_install_mark_rows_col_dirty (PsppSheetView *tree_view)
-{
- install_presize_handler (tree_view);
-}
-
-/* Drag-and-drop */
-
-static void
-set_source_row (GdkDragContext *context,
- GtkTreeModel *model,
- GtkTreePath *source_row)
-{
- g_object_set_data_full (G_OBJECT (context),
- "gtk-tree-view-source-row",
- source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
- (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
-}
-
-static GtkTreePath*
-get_source_row (GdkDragContext *context)
-{
- GtkTreeRowReference *ref =
- g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
-
- if (ref)
- return gtk_tree_row_reference_get_path (ref);
- else
- return NULL;
-}
-
-typedef struct
-{
- GtkTreeRowReference *dest_row;
- guint path_down_mode : 1;
- guint empty_view_drop : 1;
- guint drop_append_mode : 1;
-}
-DestRow;
-
-static void
-dest_row_free (gpointer data)
-{
- DestRow *dr = (DestRow *)data;
-
- gtk_tree_row_reference_free (dr->dest_row);
- g_slice_free (DestRow, dr);
-}
-
-static void
-set_dest_row (GdkDragContext *context,
- GtkTreeModel *model,
- GtkTreePath *dest_row,
- gboolean path_down_mode,
- gboolean empty_view_drop,
- gboolean drop_append_mode)
-{
- DestRow *dr;
-
- if (!dest_row)
- {
- g_object_set_data_full (G_OBJECT (context), "gtk-tree-view-dest-row",
- NULL, NULL);
- return;
- }
-
- dr = g_slice_new (DestRow);
-
- dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
- dr->path_down_mode = path_down_mode != FALSE;
- dr->empty_view_drop = empty_view_drop != FALSE;
- dr->drop_append_mode = drop_append_mode != FALSE;
-
- g_object_set_data_full (G_OBJECT (context), "gtk-tree-view-dest-row",
- dr, (GDestroyNotify) dest_row_free);
-}
-
-static GtkTreePath*
-get_dest_row (GdkDragContext *context,
- gboolean *path_down_mode)
-{
- DestRow *dr =
- g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
-
- if (dr)
- {
- GtkTreePath *path = NULL;
-
- if (path_down_mode)
- *path_down_mode = dr->path_down_mode;
-
- if (dr->dest_row)
- path = gtk_tree_row_reference_get_path (dr->dest_row);
- else if (dr->empty_view_drop)
- path = gtk_tree_path_new_from_indices (0, -1);
- else
- path = NULL;
-
- if (path && dr->drop_append_mode)
- gtk_tree_path_next (path);
-
- return path;
- }
- else
- return NULL;
-}
-
-/* Get/set whether drag_motion requested the drag data and
- * drag_data_received should thus not actually insert the data,
- * since the data doesn't result from a drop.
- */
-static void
-set_status_pending (GdkDragContext *context,
- GdkDragAction suggested_action)
-{
- g_object_set_data (G_OBJECT (context),
- "gtk-tree-view-status-pending",
- GINT_TO_POINTER (suggested_action));
-}
-
-static GdkDragAction
-get_status_pending (GdkDragContext *context)
-{
- return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
- "gtk-tree-view-status-pending"));
-}
-
-static TreeViewDragInfo*
-get_info (PsppSheetView *tree_view)
-{
- return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
-}
-
-static void
-destroy_info (TreeViewDragInfo *di)
-{
- g_slice_free (TreeViewDragInfo, di);
-}
-
-static TreeViewDragInfo*
-ensure_info (PsppSheetView *tree_view)
-{
- TreeViewDragInfo *di;
-
- di = get_info (tree_view);
-
- if (di == NULL)
- {
- di = g_slice_new0 (TreeViewDragInfo);
-
- g_object_set_data_full (G_OBJECT (tree_view),
- "gtk-tree-view-drag-info",
- di,
- (GDestroyNotify) destroy_info);
- }
-
- return di;
-}
-
-static void
-remove_info (PsppSheetView *tree_view)
-{
- g_object_set_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info", NULL);
-}
-
-#if 0
-static gint
-drag_scan_timeout (gpointer data)
-{
- PsppSheetView *tree_view;
- gint x, y;
- GdkModifierType state;
- GtkTreePath *path = NULL;
- PsppSheetViewColumn *column = NULL;
- GdkRectangle visible_rect;
-
- GDK_THREADS_ENTER ();
-
- tree_view = PSPP_SHEET_VIEW (data);
-
- gdk_window_get_pointer (tree_view->priv->bin_window,
- &x, &y, &state);
-
- pspp_sheet_view_get_visible_rect (tree_view, &visible_rect);
-
- /* See if we are near the edge. */
- if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
- (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
- (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
- (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
- {
- pspp_sheet_view_get_path_at_pos (tree_view,
- tree_view->priv->bin_window,
- x, y,
- &path,
- &column,
- NULL,
- NULL);
-
- if (path != NULL)
- {
- pspp_sheet_view_scroll_to_cell (tree_view,
- path,
- column,
- TRUE,
- 0.5, 0.5);
-
- gtk_tree_path_free (path);
- }
- }
-
- GDK_THREADS_LEAVE ();
-
- return TRUE;
-}
-#endif /* 0 */
-
-static void
-add_scroll_timeout (PsppSheetView *tree_view)
-{
- if (tree_view->priv->scroll_timeout == 0)
- {
- tree_view->priv->scroll_timeout =
- gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
- }
-}
-
-static void
-remove_scroll_timeout (PsppSheetView *tree_view)
-{
- if (tree_view->priv->scroll_timeout != 0)
- {
- g_source_remove (tree_view->priv->scroll_timeout);
- tree_view->priv->scroll_timeout = 0;
- }
-}
-
-static gboolean
-check_model_dnd (GtkTreeModel *model,
- GType required_iface,
- const gchar *signal)
-{
- if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
- {
- g_warning ("You must override the default '%s' handler "
- "on PsppSheetView when using models that don't support "
- "the %s interface and enabling drag-and-drop. The simplest way to do this "
- "is to connect to '%s' and call "
- "g_signal_stop_emission_by_name() in your signal handler to prevent "
- "the default handler from running. Look at the source code "
- "for the default handler in gtktreeview.c to get an idea what "
- "your handler should do. (gtktreeview.c is in the GTK source "
- "code.) If you're using GTK from a language other than C, "
- "there may be a more natural way to override default handlers, e.g. via derivation.",
- signal, g_type_name (required_iface), signal);
- return FALSE;
- }
- else
- return TRUE;
-}
-
-static gboolean
-scroll_row_timeout (gpointer data)
-{
- PsppSheetView *tree_view = data;
-
- pspp_sheet_view_horizontal_autoscroll (tree_view);
- pspp_sheet_view_vertical_autoscroll (tree_view);
-
- if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
- pspp_sheet_view_update_rubber_band (tree_view);
-
- return TRUE;
-}
-
-/* Returns TRUE if event should not be propagated to parent widgets */
-static gboolean
-set_destination_row (PsppSheetView *tree_view,
- GdkDragContext *context,
- /* coordinates relative to the widget */
- gint x,
- gint y,
- GdkDragAction *suggested_action,
- GdkAtom *target)
-{
- GtkTreePath *path = NULL;
- PsppSheetViewDropPosition pos;
- PsppSheetViewDropPosition old_pos;
- TreeViewDragInfo *di;
- GtkWidget *widget;
- GtkTreePath *old_dest_path = NULL;
- gboolean can_drop = FALSE;
-
- *suggested_action = 0;
- *target = GDK_NONE;
-
- widget = GTK_WIDGET (tree_view);
-
- di = get_info (tree_view);
-
- if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
- {
- /* someone unset us as a drag dest, note that if
- * we return FALSE drag_leave isn't called
- */
-
- pspp_sheet_view_set_drag_dest_row (tree_view,
- NULL,
- PSPP_SHEET_VIEW_DROP_BEFORE);
-
- remove_scroll_timeout (PSPP_SHEET_VIEW (widget));
-
- return FALSE; /* no longer a drop site */
- }
-
- *target = gtk_drag_dest_find_target (widget, context,
- gtk_drag_dest_get_target_list (widget));
- if (*target == GDK_NONE)
- {
- return FALSE;
- }
-
- if (!pspp_sheet_view_get_dest_row_at_pos (tree_view,
- x, y,
- &path,
- &pos))
- {
- gint n_children;
- GtkTreeModel *model;
-
- /* the row got dropped on empty space, let's setup a special case
- */
-
- if (path)
- gtk_tree_path_free (path);
-
- model = pspp_sheet_view_get_model (tree_view);
-
- n_children = gtk_tree_model_iter_n_children (model, NULL);
- if (n_children)
- {
- pos = PSPP_SHEET_VIEW_DROP_AFTER;
- path = gtk_tree_path_new_from_indices (n_children - 1, -1);
- }
- else
- {
- pos = PSPP_SHEET_VIEW_DROP_BEFORE;
- path = gtk_tree_path_new_from_indices (0, -1);
- }
-
- can_drop = TRUE;
-
- goto out;
- }
-
- g_assert (path);
-
- /* If we left the current row's "open" zone, unset the timeout for
- * opening the row
- */
- pspp_sheet_view_get_drag_dest_row (tree_view,
- &old_dest_path,
- &old_pos);
-
- if (old_dest_path)
- gtk_tree_path_free (old_dest_path);
-
- if (TRUE /* FIXME if the location droppable predicate */)
- {
- can_drop = TRUE;
- }
-
-out:
- if (can_drop)
- {
- GtkWidget *source_widget;
-
- *suggested_action = gdk_drag_context_get_suggested_action (context);
- source_widget = gtk_drag_get_source_widget (context);
-
- if (source_widget == widget)
- {
- /* Default to MOVE, unless the user has
- * pressed ctrl or shift to affect available actions
- */
- if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
- *suggested_action = GDK_ACTION_MOVE;
- }
-
- pspp_sheet_view_set_drag_dest_row (PSPP_SHEET_VIEW (widget),
- path, pos);
- }
- else
- {
- /* can't drop here */
- pspp_sheet_view_set_drag_dest_row (PSPP_SHEET_VIEW (widget),
- NULL,
- PSPP_SHEET_VIEW_DROP_BEFORE);
- }
-
- if (path)
- gtk_tree_path_free (path);
-
- return TRUE;
-}
-
-static GtkTreePath*
-get_logical_dest_row (PsppSheetView *tree_view,
- gboolean *path_down_mode,
- gboolean *drop_append_mode)
-{
- /* adjust path to point to the row the drop goes in front of */
- GtkTreePath *path = NULL;
- PsppSheetViewDropPosition pos;
-
- g_return_val_if_fail (path_down_mode != NULL, NULL);
- g_return_val_if_fail (drop_append_mode != NULL, NULL);
-
- *path_down_mode = FALSE;
- *drop_append_mode = 0;
-
- pspp_sheet_view_get_drag_dest_row (tree_view, &path, &pos);
-
- if (path == NULL)
- return NULL;
-
- if (pos == PSPP_SHEET_VIEW_DROP_BEFORE)
- ; /* do nothing */
- else if (pos == PSPP_SHEET_VIEW_DROP_INTO_OR_BEFORE ||
- pos == PSPP_SHEET_VIEW_DROP_INTO_OR_AFTER)
- *path_down_mode = TRUE;
- else
- {
- GtkTreeIter iter;
- GtkTreeModel *model = pspp_sheet_view_get_model (tree_view);
-
- g_assert (pos == PSPP_SHEET_VIEW_DROP_AFTER);
-
- if (!gtk_tree_model_get_iter (model, &iter, path) ||
- !gtk_tree_model_iter_next (model, &iter))
- *drop_append_mode = 1;
- else
- {
- *drop_append_mode = 0;
- gtk_tree_path_next (path);
- }
- }
-
- return path;
-}
-
-static gboolean
-pspp_sheet_view_maybe_begin_dragging_row (PsppSheetView *tree_view,
- GdkEventMotion *event)
-{
- GtkWidget *widget = GTK_WIDGET (tree_view);
- GdkDragContext *context;
- TreeViewDragInfo *di;
- GtkTreePath *path = NULL;
- gint button;
- gint cell_x, cell_y;
- GtkTreeModel *model;
- gboolean retval = FALSE;
-
- di = get_info (tree_view);
-
- if (di == NULL || !di->source_set)
- goto out;
-
- if (tree_view->priv->pressed_button < 0)
- goto out;
-
- if (!gtk_drag_check_threshold (widget,
- tree_view->priv->press_start_x,
- tree_view->priv->press_start_y,
- event->x, event->y))
- goto out;
-
- model = pspp_sheet_view_get_model (tree_view);
-
- if (model == NULL)
- goto out;
-
- button = tree_view->priv->pressed_button;
- tree_view->priv->pressed_button = -1;
-
- pspp_sheet_view_get_path_at_pos (tree_view,
- tree_view->priv->press_start_x,
- tree_view->priv->press_start_y,
- &path,
- NULL,
- &cell_x,
- &cell_y);
-
- if (path == NULL)
- goto out;
-
- if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
- !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
- path))
- goto out;
-
- if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
- goto out;
-
- /* Now we can begin the drag */
-
- retval = TRUE;
-
- context = gtk_drag_begin (widget,
- gtk_drag_source_get_target_list (widget),
- di->source_actions,
- button,
- (GdkEvent*)event);
-
- set_source_row (context, model, path);
-
- out:
- if (path)
- gtk_tree_path_free (path);
-
- return retval;
-}
-
-
-
-static void
-pspp_sheet_view_drag_begin (GtkWidget *widget,
- GdkDragContext *context)
-{
-}
-
-
-static void
-pspp_sheet_view_drag_end (GtkWidget *widget,
- GdkDragContext *context)
-{
- /* do nothing */
-}
-
-/* Default signal implementations for the drag signals */
-static void
-pspp_sheet_view_drag_data_get (GtkWidget *widget,
- GdkDragContext *context,
- GtkSelectionData *selection_data,
- guint info,
- guint time)
-{
- PsppSheetView *tree_view;
- GtkTreeModel *model;
- TreeViewDragInfo *di;
- GtkTreePath *source_row;
-
- tree_view = PSPP_SHEET_VIEW (widget);
-
- model = pspp_sheet_view_get_model (tree_view);
-
- if (model == NULL)
- return;
-
- di = get_info (PSPP_SHEET_VIEW (widget));
-
- if (di == NULL)
- return;
-
- source_row = get_source_row (context);
-
- if (source_row == NULL)
- return;
-
- /* We can implement the GTK_TREE_MODEL_ROW target generically for
- * any model; for DragSource models there are some other targets
- * we also support.
- */
-
- if (GTK_IS_TREE_DRAG_SOURCE (model) &&
- gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
- source_row,
- selection_data))
- goto done;
-
- /* If drag_data_get does nothing, try providing row data. */
- if (gtk_selection_data_get_target (selection_data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
- {
- gtk_tree_set_row_drag_data (selection_data,
- model,
- source_row);
- }
-
- done:
- gtk_tree_path_free (source_row);
-}
-
-
-static void
-pspp_sheet_view_drag_data_delete (GtkWidget *widget,
- GdkDragContext *context)
-{
- TreeViewDragInfo *di;
- GtkTreeModel *model;
- PsppSheetView *tree_view;
- GtkTreePath *source_row;
-
- tree_view = PSPP_SHEET_VIEW (widget);
- model = pspp_sheet_view_get_model (tree_view);
-
- if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
- return;
-
- di = get_info (tree_view);
-
- if (di == NULL)
- return;
-
- source_row = get_source_row (context);
-
- if (source_row == NULL)
- return;
-
- gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
- source_row);
-
- gtk_tree_path_free (source_row);
-
- set_source_row (context, NULL, NULL);
-}
-
-static void
-pspp_sheet_view_drag_leave (GtkWidget *widget,
- GdkDragContext *context,
- guint time)
-{
- /* unset any highlight row */
- pspp_sheet_view_set_drag_dest_row (PSPP_SHEET_VIEW (widget),
- NULL,
- PSPP_SHEET_VIEW_DROP_BEFORE);
-
- remove_scroll_timeout (PSPP_SHEET_VIEW (widget));
-}
-
-
-static gboolean
-pspp_sheet_view_drag_motion (GtkWidget *widget,
- GdkDragContext *context,
- /* coordinates relative to the widget */
- gint x,
- gint y,
- guint time)
-{
- gboolean empty;
- GtkTreePath *path = NULL;
- PsppSheetViewDropPosition pos;
- PsppSheetView *tree_view;
- GdkDragAction suggested_action = 0;
- GdkAtom target;
-
- tree_view = PSPP_SHEET_VIEW (widget);
-
- if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
- return FALSE;
-
- pspp_sheet_view_get_drag_dest_row (tree_view, &path, &pos);
-
- /* we only know this *after* set_desination_row */
- empty = tree_view->priv->empty_view_drop;
-
- if (path == NULL && !empty)
- {
- /* Can't drop here. */
- gdk_drag_status (context, 0, time);
- }
- else
- {
- if (tree_view->priv->open_dest_timeout == 0 &&
- (pos == PSPP_SHEET_VIEW_DROP_INTO_OR_AFTER ||
- pos == PSPP_SHEET_VIEW_DROP_INTO_OR_BEFORE))
- {
- /* Nothing. */
- }
- else
- {
- add_scroll_timeout (tree_view);
- }
-
- if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
- {
- /* Request data so we can use the source row when
- * determining whether to accept the drop
- */
- set_status_pending (context, suggested_action);
- gtk_drag_get_data (widget, context, target, time);
- }
- else
- {
- set_status_pending (context, 0);
- gdk_drag_status (context, suggested_action, time);
- }
- }
-
- if (path)
- gtk_tree_path_free (path);
-
- return TRUE;
-}
-
-
-static gboolean
-pspp_sheet_view_drag_drop (GtkWidget *widget,
- GdkDragContext *context,
- /* coordinates relative to the widget */
- gint x,
- gint y,
- guint time)
-{
- PsppSheetView *tree_view;
- GtkTreePath *path;
- GdkDragAction suggested_action = 0;
- GdkAtom target = GDK_NONE;
- TreeViewDragInfo *di;
- GtkTreeModel *model;
- gboolean path_down_mode;
- gboolean drop_append_mode;
-
- tree_view = PSPP_SHEET_VIEW (widget);
-
- model = pspp_sheet_view_get_model (tree_view);
-
- remove_scroll_timeout (PSPP_SHEET_VIEW (widget));
-
- di = get_info (tree_view);
-
- if (di == NULL)
- return FALSE;
-
- if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
- return FALSE;
-
- if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
- return FALSE;
-
- path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
-
- if (target != GDK_NONE && path != NULL)
- {
- /* in case a motion had requested drag data, change things so we
- * treat drag data receives as a drop.
- */
- set_status_pending (context, 0);
- set_dest_row (context, model, path,
- path_down_mode, tree_view->priv->empty_view_drop,
- drop_append_mode);
- }
-
- if (path)
- gtk_tree_path_free (path);
-
- /* Unset this thing */
- pspp_sheet_view_set_drag_dest_row (PSPP_SHEET_VIEW (widget),
- NULL,
- PSPP_SHEET_VIEW_DROP_BEFORE);
-
- if (target != GDK_NONE)
- {
- gtk_drag_get_data (widget, context, target, time);
- return TRUE;
- }
- else
- return FALSE;
-}
-
-static void
-pspp_sheet_view_drag_data_received (GtkWidget *widget,
- GdkDragContext *context,
- /* coordinates relative to the widget */
- gint x,
- gint y,
- GtkSelectionData *selection_data,
- guint info,
- guint time)
-{
- GtkTreePath *path;
- TreeViewDragInfo *di;
- gboolean accepted = FALSE;
- GtkTreeModel *model;
- PsppSheetView *tree_view;
- GtkTreePath *dest_row;
- GdkDragAction suggested_action;
- gboolean path_down_mode;
- gboolean drop_append_mode;
-
- tree_view = PSPP_SHEET_VIEW (widget);
-
- model = pspp_sheet_view_get_model (tree_view);
-
- if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
- return;
-
- di = get_info (tree_view);
-
- if (di == NULL)
- return;
-
- suggested_action = get_status_pending (context);
-
- if (suggested_action)
- {
- /* We are getting this data due to a request in drag_motion,
- * rather than due to a request in drag_drop, so we are just
- * supposed to call drag_status, not actually paste in the
- * data.
- */
- path = get_logical_dest_row (tree_view, &path_down_mode,
- &drop_append_mode);
-
- if (path == NULL)
- suggested_action = 0;
- else if (path_down_mode)
- gtk_tree_path_down (path);
-
- if (suggested_action)
- {
- if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
- path,
- selection_data))
- {
- if (path_down_mode)
- {
- path_down_mode = FALSE;
- gtk_tree_path_up (path);
-
- if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
- path,
- selection_data))
- suggested_action = 0;
- }
- else
- suggested_action = 0;
- }
- }
-
- gdk_drag_status (context, suggested_action, time);
-
- if (path)
- gtk_tree_path_free (path);
-
- /* If you can't drop, remove user drop indicator until the next motion */
- if (suggested_action == 0)
- pspp_sheet_view_set_drag_dest_row (PSPP_SHEET_VIEW (widget),
- NULL,
- PSPP_SHEET_VIEW_DROP_BEFORE);
-
- return;
- }
-
- dest_row = get_dest_row (context, &path_down_mode);
-
- if (dest_row == NULL)
- return;
-
- if (gtk_selection_data_get_length (selection_data) >= 0)
- {
- if (path_down_mode)
- {
- gtk_tree_path_down (dest_row);
- if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
- dest_row, selection_data))
- gtk_tree_path_up (dest_row);
- }
- }
-
- if (gtk_selection_data_get_length (selection_data) >= 0)
- {
- if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
- dest_row,
- selection_data))
- accepted = TRUE;
- }
-
- gtk_drag_finish (context,
- accepted,
- (gdk_drag_context_get_actions (context) == GDK_ACTION_MOVE),
- time);
-
- if (gtk_tree_path_get_depth (dest_row) == 1
- && gtk_tree_path_get_indices (dest_row)[0] == 0)
- {
- /* special special case drag to "0", scroll to first item */
- if (!tree_view->priv->scroll_to_path)
- pspp_sheet_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
- }
-
- gtk_tree_path_free (dest_row);
-
- /* drop dest_row */
- set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
-}
-
-
-
-/* GtkContainer Methods
- */
-
-
-static void
-pspp_sheet_view_remove (GtkContainer *container,
- GtkWidget *widget)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (container);
- PsppSheetViewChild *child = NULL;
- GList *tmp_list;
-
- tmp_list = tree_view->priv->children;
- while (tmp_list)
- {
- child = tmp_list->data;
- if (child->widget == widget)
- {
- gtk_widget_unparent (widget);
-
- tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
- g_list_free_1 (tmp_list);
- g_slice_free (PsppSheetViewChild, child);
- return;
- }
-
- tmp_list = tmp_list->next;
- }
-
- tmp_list = tree_view->priv->columns;
-
- while (tmp_list)
- {
- PsppSheetViewColumn *column;
- column = tmp_list->data;
- if (column->button == widget)
- {
- gtk_widget_unparent (widget);
- return;
- }
- tmp_list = tmp_list->next;
- }
-}
-
-static void
-pspp_sheet_view_forall (GtkContainer *container,
- gboolean include_internals,
- GtkCallback callback,
- gpointer callback_data)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (container);
- PsppSheetViewChild *child = NULL;
- PsppSheetViewColumn *column;
- GList *tmp_list;
-
- tmp_list = tree_view->priv->children;
- while (tmp_list)
- {
- child = tmp_list->data;
- tmp_list = tmp_list->next;
-
- (* callback) (child->widget, callback_data);
- }
- if (include_internals == FALSE)
- return;
-
- for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
- {
- column = tmp_list->data;
-
- if (column->button)
- (* callback) (column->button, callback_data);
- }
-}
-
-/* Returns TRUE if the treeview contains no "special" (editable or activatable)
- * cells. If so we draw one big row-spanning focus rectangle.
- */
-static gboolean
-pspp_sheet_view_has_special_cell (PsppSheetView *tree_view)
-{
- GList *list;
-
- if (tree_view->priv->special_cells != PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT)
- return tree_view->priv->special_cells = PSPP_SHEET_VIEW_SPECIAL_CELLS_YES;
-
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- if (!((PsppSheetViewColumn *)list->data)->visible)
- continue;
- if (_pspp_sheet_view_column_count_special_cells (list->data))
- return TRUE;
- }
-
- return FALSE;
-}
-
-static void
-pspp_sheet_view_focus_column (PsppSheetView *tree_view,
- PsppSheetViewColumn *focus_column,
- gboolean clamp_column_visible)
-{
- g_return_if_fail (focus_column != NULL);
-
- tree_view->priv->focus_column = focus_column;
-
- if (gtk_container_get_focus_child (GTK_CONTAINER (tree_view)) != focus_column->button)
- gtk_widget_grab_focus (focus_column->button);
-
- if (clamp_column_visible)
- pspp_sheet_view_clamp_column_visible (tree_view, focus_column, FALSE);
-}
-
-/* Returns TRUE if the focus is within the headers, after the focus operation is
- * done
- */
-static gboolean
-pspp_sheet_view_header_focus (PsppSheetView *tree_view,
- GtkDirectionType dir,
- gboolean clamp_column_visible)
-{
- GtkWidget *focus_child;
- PsppSheetViewColumn *focus_column;
- GList *last_column, *first_column;
- GList *tmp_list;
- gboolean rtl;
-
- if (! PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_HEADERS_VISIBLE))
- return FALSE;
-
- focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
-
- first_column = tree_view->priv->columns;
- while (first_column)
- {
- PsppSheetViewColumn *c = PSPP_SHEET_VIEW_COLUMN (first_column->data);
-
- if (pspp_sheet_view_column_can_focus (c) && c->visible)
- break;
- first_column = first_column->next;
- }
-
- /* No headers are visible, or are focusable. We can't focus in or out.
- */
- if (first_column == NULL)
- return FALSE;
-
- last_column = g_list_last (tree_view->priv->columns);
- while (last_column)
- {
- PsppSheetViewColumn *c = PSPP_SHEET_VIEW_COLUMN (last_column->data);
-
- if (pspp_sheet_view_column_can_focus (c) && c->visible)
- break;
- last_column = last_column->prev;
- }
-
-
- rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
- switch (dir)
- {
- case GTK_DIR_TAB_BACKWARD:
- case GTK_DIR_TAB_FORWARD:
- case GTK_DIR_UP:
- case GTK_DIR_DOWN:
- if (focus_child == NULL)
- {
- if (tree_view->priv->focus_column != NULL &&
- pspp_sheet_view_column_can_focus (tree_view->priv->focus_column))
- focus_column = tree_view->priv->focus_column;
- else
- focus_column = first_column->data;
- pspp_sheet_view_focus_column (tree_view, focus_column,
- clamp_column_visible);
- return TRUE;
- }
- return FALSE;
-
- case GTK_DIR_LEFT:
- case GTK_DIR_RIGHT:
- if (focus_child == NULL)
- {
- if (tree_view->priv->focus_column != NULL)
- focus_column = tree_view->priv->focus_column;
- else if (dir == GTK_DIR_LEFT)
- focus_column = last_column->data;
- else
- focus_column = first_column->data;
- pspp_sheet_view_focus_column (tree_view, focus_column,
- clamp_column_visible);
- return TRUE;
- }
-
- if (gtk_widget_child_focus (focus_child, dir))
- {
- /* The focus moves inside the button. */
- /* This is probably a great example of bad UI */
- if (clamp_column_visible)
- pspp_sheet_view_clamp_column_visible (tree_view,
- tree_view->priv->focus_column,
- FALSE);
- return TRUE;
- }
-
- /* We need to move the focus among the row of buttons. */
- for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
- if (PSPP_SHEET_VIEW_COLUMN (tmp_list->data)->button == focus_child)
- break;
-
- if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
- || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
- {
- gtk_widget_error_bell (GTK_WIDGET (tree_view));
- return TRUE;
- }
-
- while (tmp_list)
- {
- PsppSheetViewColumn *column;
-
- if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
- tmp_list = tmp_list->next;
- else
- tmp_list = tmp_list->prev;
-
- if (tmp_list == NULL)
- {
- g_warning ("Internal button not found");
- break;
- }
- column = tmp_list->data;
- if (column->visible &&
- pspp_sheet_view_column_can_focus (column))
- {
- if (column->button)
- {
- pspp_sheet_view_focus_column (tree_view, column,
- clamp_column_visible);
- return TRUE;
- }
- }
- }
- return FALSE;
-
- default:
- g_assert_not_reached ();
- break;
- }
-
- return FALSE;
-}
-
-/* This function returns in 'path' the first focusable path, if the given path
- * is already focusable, it's the returned one.
- *
- */
-static gboolean
-search_first_focusable_path (PsppSheetView *tree_view,
- GtkTreePath **path,
- gboolean search_forward,
- int *new_node)
-{
- /* XXX this function is trivial given that the sheetview doesn't support
- separator rows */
- int node = -1;
-
- if (!path || !*path)
- return FALSE;
-
- _pspp_sheet_view_find_node (tree_view, *path, &node);
-
- if (node < 0)
- return FALSE;
-
- if (new_node)
- *new_node = node;
-
- return (*path != NULL);
-}
-
-static gint
-pspp_sheet_view_focus (GtkWidget *widget,
- GtkDirectionType direction)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
- GtkContainer *container = GTK_CONTAINER (widget);
- GtkWidget *focus_child;
-
- if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
- return FALSE;
-
- focus_child = gtk_container_get_focus_child (container);
-
- pspp_sheet_view_stop_editing (PSPP_SHEET_VIEW (widget), FALSE);
- /* Case 1. Headers currently have focus. */
- if (focus_child)
- {
- switch (direction)
- {
- case GTK_DIR_LEFT:
- case GTK_DIR_RIGHT:
- pspp_sheet_view_header_focus (tree_view, direction, TRUE);
- return TRUE;
- case GTK_DIR_TAB_BACKWARD:
- case GTK_DIR_UP:
- return FALSE;
- case GTK_DIR_TAB_FORWARD:
- case GTK_DIR_DOWN:
- gtk_widget_grab_focus (widget);
- return TRUE;
- default:
- g_assert_not_reached ();
- return FALSE;
- }
- }
-
- /* Case 2. We don't have focus at all. */
- if (!gtk_widget_has_focus (widget))
- {
- if (!pspp_sheet_view_header_focus (tree_view, direction, FALSE))
- gtk_widget_grab_focus (widget);
- return TRUE;
- }
-
- /* Case 3. We have focus already. */
- if (direction == GTK_DIR_TAB_BACKWARD)
- return (pspp_sheet_view_header_focus (tree_view, direction, FALSE));
- else if (direction == GTK_DIR_TAB_FORWARD)
- return FALSE;
-
- /* Other directions caught by the keybindings */
- gtk_widget_grab_focus (widget);
- return TRUE;
-}
-
-static void
-pspp_sheet_view_grab_focus (GtkWidget *widget)
-{
- GTK_WIDGET_CLASS (pspp_sheet_view_parent_class)->grab_focus (widget);
-
- pspp_sheet_view_focus_to_cursor (PSPP_SHEET_VIEW (widget));
-}
-
-static void
-pspp_sheet_view_style_updated (GtkWidget *widget)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
- GList *list;
- PsppSheetViewColumn *column;
- GtkStyleContext *context;
-
- GTK_WIDGET_CLASS (pspp_sheet_view_parent_class)->style_updated (widget);
-
- if (gtk_widget_get_realized (widget))
- {
- context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
- gtk_style_context_set_background (context, gtk_widget_get_window (GTK_WIDGET (tree_view)));
- gtk_style_context_set_background (context, tree_view->priv->header_window);
- pspp_sheet_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
- }
-
- gtk_widget_style_get (widget,
- "expander-size", &tree_view->priv->expander_size,
- NULL);
- tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
-
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- column = list->data;
- _pspp_sheet_view_column_cell_set_dirty (column);
- }
-
- tree_view->priv->fixed_height = -1;
-
- /* Invalidate cached button style. */
- if (tree_view->priv->button_style)
- {
- g_object_unref (tree_view->priv->button_style);
- tree_view->priv->button_style = NULL;
- }
-
- gtk_widget_queue_resize (widget);
-}
-
-
-static void
-pspp_sheet_view_set_focus_child (GtkContainer *container,
- GtkWidget *child)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (container);
- GList *list;
-
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- if (PSPP_SHEET_VIEW_COLUMN (list->data)->button == child)
- {
- tree_view->priv->focus_column = PSPP_SHEET_VIEW_COLUMN (list->data);
- break;
- }
- }
-
- GTK_CONTAINER_CLASS (pspp_sheet_view_parent_class)->set_focus_child (container, child);
-}
-
-static void
-pspp_sheet_view_set_adjustments (PsppSheetView *tree_view,
- GtkAdjustment *hadj,
- GtkAdjustment *vadj)
-{
- gboolean need_adjust = FALSE;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- if (hadj)
- g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
- else
- hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
- if (vadj)
- g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
- else
- vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
-
- if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
- {
- g_signal_handlers_disconnect_by_func (tree_view->priv->hadjustment,
- pspp_sheet_view_adjustment_changed,
- tree_view);
- g_object_unref (tree_view->priv->hadjustment);
- }
-
- if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
- {
- g_signal_handlers_disconnect_by_func (tree_view->priv->vadjustment,
- pspp_sheet_view_adjustment_changed,
- tree_view);
- g_object_unref (tree_view->priv->vadjustment);
- }
-
- if (tree_view->priv->hadjustment != hadj)
- {
- tree_view->priv->hadjustment = hadj;
- g_object_ref_sink (tree_view->priv->hadjustment);
-
- g_signal_connect (tree_view->priv->hadjustment, "value-changed",
- G_CALLBACK (pspp_sheet_view_adjustment_changed),
- tree_view);
- need_adjust = TRUE;
- }
-
- if (tree_view->priv->vadjustment != vadj)
- {
- tree_view->priv->vadjustment = vadj;
- g_object_ref_sink (tree_view->priv->vadjustment);
-
- g_signal_connect (tree_view->priv->vadjustment, "value-changed",
- G_CALLBACK (pspp_sheet_view_adjustment_changed),
- tree_view);
- need_adjust = TRUE;
- }
-
- if (need_adjust)
- pspp_sheet_view_adjustment_changed (NULL, tree_view);
-}
-
-
-static gboolean
-pspp_sheet_view_real_move_cursor (PsppSheetView *tree_view,
- GtkMovementStep step,
- gint count)
-{
- PsppSheetSelectMode mode;
- GdkModifierType state;
-
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
- g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
- step == GTK_MOVEMENT_VISUAL_POSITIONS ||
- step == GTK_MOVEMENT_DISPLAY_LINES ||
- step == GTK_MOVEMENT_PAGES ||
- step == GTK_MOVEMENT_BUFFER_ENDS ||
- step == GTK_MOVEMENT_DISPLAY_LINE_ENDS, FALSE);
-
- if (tree_view->priv->row_count == 0)
- return FALSE;
- if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
- return FALSE;
-
- pspp_sheet_view_stop_editing (tree_view, FALSE);
- PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS);
- gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-
- mode = 0;
- if (gtk_get_current_event_state (&state))
- {
- if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
- mode |= PSPP_SHEET_SELECT_MODE_TOGGLE;
- if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
- mode |= PSPP_SHEET_SELECT_MODE_EXTEND;
- }
- /* else we assume not pressed */
-
- switch (step)
- {
- case GTK_MOVEMENT_LOGICAL_POSITIONS:
- pspp_sheet_view_move_cursor_tab (tree_view, count);
- break;
- case GTK_MOVEMENT_VISUAL_POSITIONS:
- pspp_sheet_view_move_cursor_left_right (tree_view, count, mode);
- break;
- case GTK_MOVEMENT_DISPLAY_LINES:
- pspp_sheet_view_move_cursor_up_down (tree_view, count, mode);
- break;
- case GTK_MOVEMENT_PAGES:
- pspp_sheet_view_move_cursor_page_up_down (tree_view, count, mode);
- break;
- case GTK_MOVEMENT_BUFFER_ENDS:
- pspp_sheet_view_move_cursor_start_end (tree_view, count, mode);
- break;
- case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
- pspp_sheet_view_move_cursor_line_start_end (tree_view, count, mode);
- break;
- default:
- g_assert_not_reached ();
- }
-
- return TRUE;
-}
-
-static void
-pspp_sheet_view_put (PsppSheetView *tree_view,
- GtkWidget *child_widget,
- GtkTreePath *path,
- PsppSheetViewColumn *column)
-{
- PsppSheetViewChild *child;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
- g_return_if_fail (GTK_IS_WIDGET (child_widget));
-
- child = g_slice_new (PsppSheetViewChild);
-
- child->widget = child_widget;
- _pspp_sheet_view_find_node (tree_view, path, &child->node);
- if (child->node < 0)
- {
- g_assert_not_reached ();
- }
- child->column = column;
-
- tree_view->priv->children = g_list_append (tree_view->priv->children, child);
-
- if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
- gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
-
- gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
-}
-
-/* TreeModel Callbacks
- */
-
-static void
-pspp_sheet_view_row_changed (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer data)
-{
- PsppSheetView *tree_view = (PsppSheetView *)data;
- int node;
- gboolean free_path = FALSE;
- GtkTreePath *cursor_path;
-
- g_return_if_fail (path != NULL || iter != NULL);
-
- if (tree_view->priv->cursor != NULL)
- cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
- else
- cursor_path = NULL;
-
- if (tree_view->priv->edited_column &&
- (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
- pspp_sheet_view_stop_editing (tree_view, TRUE);
-
- if (cursor_path != NULL)
- gtk_tree_path_free (cursor_path);
-
- if (path == NULL)
- {
- path = gtk_tree_model_get_path (model, iter);
- free_path = TRUE;
- }
- else if (iter == NULL)
- gtk_tree_model_get_iter (model, iter, path);
-
- _pspp_sheet_view_find_node (tree_view,
- path,
- &node);
-
- if (node >= 0)
- {
- if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
- pspp_sheet_view_node_queue_redraw (tree_view, node);
- }
-
- if (free_path)
- gtk_tree_path_free (path);
-}
-
-static void
-pspp_sheet_view_row_inserted (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer data)
-{
- PsppSheetView *tree_view = (PsppSheetView *) data;
- gint *indices;
- int tmpnode = -1;
- gint height = tree_view->priv->fixed_height;
- gboolean free_path = FALSE;
- gboolean node_visible = TRUE;
-
- g_return_if_fail (path != NULL || iter != NULL);
-
- if (path == NULL)
- {
- path = gtk_tree_model_get_path (model, iter);
- free_path = TRUE;
- }
- else if (iter == NULL)
- gtk_tree_model_get_iter (model, iter, path);
-
- tree_view->priv->row_count = gtk_tree_model_iter_n_children (model, NULL);
-
- /* Update all row-references */
- gtk_tree_row_reference_inserted (G_OBJECT (data), path);
- indices = gtk_tree_path_get_indices (path);
- tmpnode = indices[0];
-
- range_tower_insert0 (tree_view->priv->selected, tmpnode, 1);
-
- if (height > 0)
- {
- if (node_visible && node_is_visible (tree_view, tmpnode))
- gtk_widget_queue_resize (GTK_WIDGET (tree_view));
- else
- gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
- }
- else
- install_presize_handler (tree_view);
- if (free_path)
- gtk_tree_path_free (path);
-}
-
-static void
-pspp_sheet_view_row_deleted (GtkTreeModel *model,
- GtkTreePath *path,
- gpointer data)
-{
- PsppSheetView *tree_view = (PsppSheetView *)data;
- int node;
-
- g_return_if_fail (path != NULL);
-
- gtk_tree_row_reference_deleted (G_OBJECT (data), path);
-
- _pspp_sheet_view_find_node (tree_view, path, &node);
-
- if (node < 0)
- return;
-
- range_tower_delete (tree_view->priv->selected, node, 1);
-
- /* Ensure we don't have a dangling pointer to a dead node */
- ensure_unprelighted (tree_view);
-
- /* Cancel editting if we've started */
- pspp_sheet_view_stop_editing (tree_view, TRUE);
-
- if (tree_view->priv->destroy_count_func)
- {
- gint child_count = 0;
- tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
- }
-
- tree_view->priv->row_count = gtk_tree_model_iter_n_children (model, NULL);
-
- if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
- {
- gtk_tree_row_reference_free (tree_view->priv->top_row);
- tree_view->priv->top_row = NULL;
- }
-
- install_scroll_sync_handler (tree_view);
-
- gtk_widget_queue_resize (GTK_WIDGET (tree_view));
-
-#if 0
- if (helper_data.changed)
- g_signal_emit_by_name (tree_view->priv->selection, "changed");
-#endif
-}
-
-static void
-pspp_sheet_view_rows_reordered (GtkTreeModel *model,
- GtkTreePath *parent,
- GtkTreeIter *iter,
- gint *new_order,
- gpointer data)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (data);
- gint len;
-
- /* XXX need to adjust selection */
- len = gtk_tree_model_iter_n_children (model, iter);
-
- if (len < 2)
- return;
-
- gtk_tree_row_reference_reordered (G_OBJECT (data),
- parent,
- iter,
- new_order);
-
- if (gtk_tree_path_get_depth (parent) != 0)
- return;
-
- if (tree_view->priv->edited_column)
- pspp_sheet_view_stop_editing (tree_view, TRUE);
-
- /* we need to be unprelighted */
- ensure_unprelighted (tree_view);
-
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-
- pspp_sheet_view_dy_to_top_row (tree_view);
-}
-
-
-/* Internal tree functions
- */
-
-
-static void
-pspp_sheet_view_get_background_xrange (PsppSheetView *tree_view,
- PsppSheetViewColumn *column,
- gint *x1,
- gint *x2)
-{
- PsppSheetViewColumn *tmp_column = NULL;
- gint total_width;
- GList *list;
- gboolean rtl;
-
- if (x1)
- *x1 = 0;
-
- if (x2)
- *x2 = 0;
-
- rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
- total_width = 0;
- for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
- list;
- list = (rtl ? list->prev : list->next))
- {
- tmp_column = list->data;
-
- if (tmp_column == column)
- break;
-
- if (tmp_column->visible)
- total_width += tmp_column->width;
- }
-
- if (tmp_column != column)
- {
- g_warning (G_STRLOC": passed-in column isn't in the tree");
- return;
- }
-
- if (x1)
- *x1 = total_width;
-
- if (x2)
- {
- if (column->visible)
- *x2 = total_width + column->width;
- else
- *x2 = total_width; /* width of 0 */
- }
-}
-
-/* Make sure the node is visible vertically */
-static void
-pspp_sheet_view_clamp_node_visible (PsppSheetView *tree_view,
- int node)
-{
- gint node_dy, height;
- GtkTreePath *path = NULL;
-
- if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
- return;
-
- /* just return if the node is visible, avoiding a costly expose */
- node_dy = pspp_sheet_view_node_find_offset (tree_view, node);
- height = ROW_HEIGHT (tree_view);
- if (node_dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment)
- && node_dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
- + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
- return;
-
- path = _pspp_sheet_view_find_path (tree_view, node);
- if (path)
- {
- /* We process updates because we want to clear old selected items when we scroll.
- * if this is removed, we get a "selection streak" at the bottom. */
- gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
- pspp_sheet_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
- gtk_tree_path_free (path);
- }
-}
-
-static void
-pspp_sheet_view_clamp_column_visible (PsppSheetView *tree_view,
- PsppSheetViewColumn *column,
- gboolean focus_to_cell)
-{
- gint x, width;
-
- if (column == NULL)
- return;
-
- x = column->allocation.x;
- width = column->allocation.width;
-
- if (width > gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
- {
- /* The column is larger than the horizontal page size. If the
- * column has cells which can be focussed individually, then we make
- * sure the cell which gets focus is fully visible (if even the
- * focus cell is bigger than the page size, we make sure the
- * left-hand side of the cell is visible).
- *
- * If the column does not have those so-called special cells, we
- * make sure the left-hand side of the column is visible.
- */
-
- if (focus_to_cell && pspp_sheet_view_has_special_cell (tree_view))
- {
- GtkTreePath *cursor_path;
- GdkRectangle background_area, cell_area, focus_area;
-
- cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-
- pspp_sheet_view_get_cell_area (tree_view,
- cursor_path, column, &cell_area);
- pspp_sheet_view_get_background_area (tree_view,
- cursor_path, column,
- &background_area);
-
- gtk_tree_path_free (cursor_path);
-
- _pspp_sheet_view_column_get_focus_area (column,
- &background_area,
- &cell_area,
- &focus_area);
-
- x = focus_area.x;
- width = focus_area.width;
-
- if (width < gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
- {
- if ((gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment)) < (x + width))
- gtk_adjustment_set_value (tree_view->priv->hadjustment,
- x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
- else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
- gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
- }
- }
-
- gtk_adjustment_set_value (tree_view->priv->hadjustment,
- CLAMP (x,
- gtk_adjustment_get_lower (tree_view->priv->hadjustment),
- gtk_adjustment_get_upper (tree_view->priv->hadjustment)
- - gtk_adjustment_get_page_size (tree_view->priv->hadjustment)));
- }
- else
- {
- if ((gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment)) < (x + width))
- gtk_adjustment_set_value (tree_view->priv->hadjustment,
- x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
- else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
- gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
- }
-}
-
-GtkTreePath *
-_pspp_sheet_view_find_path (PsppSheetView *tree_view,
- int node)
-{
- GtkTreePath *path;
-
- path = gtk_tree_path_new ();
- if (node >= 0)
- gtk_tree_path_append_index (path, node);
- return path;
-}
-
-void
-_pspp_sheet_view_find_node (PsppSheetView *tree_view,
- GtkTreePath *path,
- int *node)
-{
- gint *indices = gtk_tree_path_get_indices (path);
- gint depth = gtk_tree_path_get_depth (path);
-
- *node = -1;
- if (depth == 0 || indices[0] < 0 || indices[0] >= tree_view->priv->row_count)
- return;
- *node = indices[0];
-}
-
-static void
-pspp_sheet_view_add_move_binding (GtkBindingSet *binding_set,
- guint keyval,
- guint modmask,
- gboolean add_shifted_binding,
- GtkMovementStep step,
- gint count)
-{
-
- gtk_binding_entry_add_signal (binding_set, keyval, modmask,
- "move-cursor", 2,
- G_TYPE_ENUM, step,
- G_TYPE_INT, count);
-
- if (add_shifted_binding)
- gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
- "move-cursor", 2,
- G_TYPE_ENUM, step,
- G_TYPE_INT, count);
-
- if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
- return;
-
- gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
- "move-cursor", 2,
- G_TYPE_ENUM, step,
- G_TYPE_INT, count);
-
- gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
- "move-cursor", 2,
- G_TYPE_ENUM, step,
- G_TYPE_INT, count);
-}
-
-static void
-pspp_sheet_view_set_column_drag_info (PsppSheetView *tree_view,
- PsppSheetViewColumn *column)
-{
- PsppSheetViewColumn *left_column;
- PsppSheetViewColumn *cur_column = NULL;
- PsppSheetViewColumnReorder *reorder;
- gboolean rtl;
- GList *tmp_list;
- gint left;
-
- /* We want to precalculate the motion list such that we know what column slots
- * are available.
- */
- left_column = NULL;
- rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
- /* First, identify all possible drop spots */
- if (rtl)
- tmp_list = g_list_last (tree_view->priv->columns);
- else
- tmp_list = g_list_first (tree_view->priv->columns);
-
- while (tmp_list)
- {
- cur_column = PSPP_SHEET_VIEW_COLUMN (tmp_list->data);
- tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
-
- if (cur_column->visible == FALSE)
- continue;
-
- /* If it's not the column moving and func tells us to skip over the column, we continue. */
- if (left_column != column && cur_column != column &&
- tree_view->priv->column_drop_func &&
- ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
- {
- left_column = cur_column;
- continue;
- }
- reorder = g_slice_new0 (PsppSheetViewColumnReorder);
- reorder->left_column = left_column;
- left_column = reorder->right_column = cur_column;
-
- tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
- }
-
- /* Add the last one */
- if (tree_view->priv->column_drop_func == NULL ||
- ((left_column != column) &&
- tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
- {
- reorder = g_slice_new0 (PsppSheetViewColumnReorder);
- reorder->left_column = left_column;
- reorder->right_column = NULL;
- tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
- }
-
- /* We quickly check to see if it even makes sense to reorder columns. */
- /* If there is nothing that can be moved, then we return */
-
- if (tree_view->priv->column_drag_info == NULL)
- return;
-
- /* We know there are always 2 slots possbile, as you can always return column. */
- /* If that's all there is, return */
- if (tree_view->priv->column_drag_info->next == NULL ||
- (tree_view->priv->column_drag_info->next->next == NULL &&
- ((PsppSheetViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
- ((PsppSheetViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
- {
- for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
- g_slice_free (PsppSheetViewColumnReorder, tmp_list->data);
- g_list_free (tree_view->priv->column_drag_info);
- tree_view->priv->column_drag_info = NULL;
- return;
- }
- /* We fill in the ranges for the columns, now that we've isolated them */
- left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
-
- for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
- {
- reorder = (PsppSheetViewColumnReorder *) tmp_list->data;
-
- reorder->left_align = left;
- if (tmp_list->next != NULL)
- {
- g_assert (tmp_list->next->data);
- left = reorder->right_align = (reorder->right_column->allocation.x +
- reorder->right_column->allocation.width +
- ((PsppSheetViewColumnReorder *)tmp_list->next->data)->left_column->allocation.x)/2;
- }
- else
- {
- gint width = gdk_window_get_width (tree_view->priv->header_window);
- reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
- }
- }
-}
-
-void
-_pspp_sheet_view_column_start_drag (PsppSheetView *tree_view,
- PsppSheetViewColumn *column)
-{
- GdkEvent *send_event;
- GtkAllocation allocation;
- gint x, y;
- GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
- GdkDisplay *display = gdk_screen_get_display (screen);
-
- g_return_if_fail (tree_view->priv->column_drag_info == NULL);
- g_return_if_fail (tree_view->priv->cur_reorder == NULL);
- g_return_if_fail (column->button);
-
- pspp_sheet_view_set_column_drag_info (tree_view, column);
-
- if (tree_view->priv->column_drag_info == NULL)
- return;
-
- if (tree_view->priv->drag_window == NULL)
- {
- GdkWindowAttr attributes;
- guint attributes_mask;
-
- attributes.window_type = GDK_WINDOW_CHILD;
- attributes.wclass = GDK_INPUT_OUTPUT;
- attributes.x = column->allocation.x;
- attributes.y = 0;
- attributes.width = column->allocation.width;
- attributes.height = column->allocation.height;
- attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
- attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
- attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL ;
-
- tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
- &attributes,
- attributes_mask);
- gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
- }
-
- gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
- gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
-
- gtk_grab_remove (column->button);
-
- send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
- send_event->crossing.send_event = TRUE;
- send_event->crossing.window = g_object_ref (gtk_button_get_event_window (GTK_BUTTON (column->button)));
- send_event->crossing.subwindow = NULL;
- send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
- send_event->crossing.time = GDK_CURRENT_TIME;
-
- gtk_propagate_event (column->button, send_event);
- gdk_event_free (send_event);
-
- send_event = gdk_event_new (GDK_BUTTON_RELEASE);
- send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
- send_event->button.send_event = TRUE;
- send_event->button.time = GDK_CURRENT_TIME;
- send_event->button.x = -1;
- send_event->button.y = -1;
- send_event->button.axes = NULL;
- send_event->button.state = 0;
- send_event->button.button = 1;
- send_event->button.device =
- gdk_device_manager_get_client_pointer (gdk_display_get_device_manager (display));
-
- send_event->button.x_root = 0;
- send_event->button.y_root = 0;
-
- gtk_propagate_event (column->button, send_event);
- gdk_event_free (send_event);
-
- /* Kids, don't try this at home */
- g_object_ref (column->button);
- gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
- gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
- gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
- g_object_unref (column->button);
-
- tree_view->priv->drag_column_x = column->allocation.x;
- allocation = column->allocation;
- allocation.x = 0;
- gtk_widget_size_allocate (column->button, &allocation);
- gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
-
- tree_view->priv->drag_column = column;
- gdk_window_show (tree_view->priv->drag_window);
-
- gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
-
- gtk_widget_grab_focus (GTK_WIDGET (tree_view));
- while (gtk_events_pending ())
- gtk_main_iteration ();
-
- PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_IN_COLUMN_DRAG);
- gdk_pointer_grab (tree_view->priv->drag_window,
- FALSE,
- GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
- NULL, NULL, GDK_CURRENT_TIME);
- gdk_keyboard_grab (tree_view->priv->drag_window,
- FALSE,
- GDK_CURRENT_TIME);
-}
-
-void
-_pspp_sheet_view_queue_draw_node (PsppSheetView *tree_view,
- int node,
- const GdkRectangle *clip_rect)
-{
- GdkRectangle rect;
- GtkAllocation allocation;
-
- if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
- return;
-
- gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
- rect.x = 0;
- rect.width = MAX (tree_view->priv->width, allocation.width);
-
- rect.y = BACKGROUND_FIRST_PIXEL (tree_view, node);
- rect.height = ROW_HEIGHT (tree_view);
-
- if (clip_rect)
- {
- GdkRectangle new_rect;
-
- gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
-
- gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
- }
- else
- {
- gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
- }
-}
-
-static void
-pspp_sheet_view_queue_draw_path (PsppSheetView *tree_view,
- GtkTreePath *path,
- const GdkRectangle *clip_rect)
-{
- int node = -1;
-
- _pspp_sheet_view_find_node (tree_view, path, &node);
-
- if (node)
- _pspp_sheet_view_queue_draw_node (tree_view, node, clip_rect);
-}
-
-static void
-pspp_sheet_view_focus_to_cursor (PsppSheetView *tree_view)
-
-{
- GtkTreePath *cursor_path;
-
- if ((tree_view->priv->row_count == 0) ||
- (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
- return;
-
- cursor_path = NULL;
- if (tree_view->priv->cursor)
- cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-
- if (cursor_path == NULL)
- {
- /* There's no cursor. Move the cursor to the first selected row, if any
- * are selected, otherwise to the first row in the sheetview.
- */
- GList *selected_rows;
- GtkTreeModel *model;
- PsppSheetSelection *selection;
-
- selection = pspp_sheet_view_get_selection (tree_view);
- selected_rows = pspp_sheet_selection_get_selected_rows (selection, &model);
-
- if (selected_rows)
- {
- /* XXX we could avoid doing O(n) work to get this result */
- cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
- g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
- g_list_free (selected_rows);
- }
- else
- {
- cursor_path = gtk_tree_path_new_first ();
- search_first_focusable_path (tree_view, &cursor_path,
- TRUE, NULL);
- }
-
- gtk_tree_row_reference_free (tree_view->priv->cursor);
- tree_view->priv->cursor = NULL;
-
- if (cursor_path)
- {
- if (tree_view->priv->selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
- tree_view->priv->selection->type == PSPP_SHEET_SELECTION_RECTANGLE)
- pspp_sheet_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE, 0);
- else
- pspp_sheet_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE, 0);
- }
- }
-
- if (cursor_path)
- {
- /* Now find a column for the cursor. */
- PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS);
-
- pspp_sheet_view_queue_draw_path (tree_view, cursor_path, NULL);
- gtk_tree_path_free (cursor_path);
-
- if (tree_view->priv->focus_column == NULL)
- {
- GList *list;
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- if (PSPP_SHEET_VIEW_COLUMN (list->data)->visible)
- {
- tree_view->priv->focus_column = PSPP_SHEET_VIEW_COLUMN (list->data);
- pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection);
- pspp_sheet_selection_select_column (tree_view->priv->selection, tree_view->priv->focus_column);
- break;
- }
- }
-
- }
- }
-}
-
-static gboolean
-pspp_sheet_view_move_cursor_up_down (PsppSheetView *tree_view,
- gint count,
- PsppSheetSelectMode mode)
-{
- gint selection_count;
- int cursor_node = -1;
- int new_cursor_node = -1;
- GtkTreePath *cursor_path = NULL;
- gboolean grab_focus = TRUE;
-
- if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
- return FALSE;
-
- cursor_path = NULL;
- if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
- /* FIXME: we lost the cursor; should we get the first? */
- return FALSE;
-
- cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
- _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node);
-
- if (cursor_node < 0)
- /* FIXME: we lost the cursor; should we get the first? */
- return FALSE;
-
- selection_count = pspp_sheet_selection_count_selected_rows (tree_view->priv->selection);
-
- if (selection_count == 0
- && tree_view->priv->selection->type != PSPP_SHEET_SELECTION_NONE
- && !(mode & PSPP_SHEET_SELECT_MODE_TOGGLE))
- {
- /* Don't move the cursor, but just select the current node */
- new_cursor_node = cursor_node;
- }
- else
- {
- if (count == -1)
- new_cursor_node = pspp_sheet_view_node_prev (tree_view, cursor_node);
- else
- new_cursor_node = pspp_sheet_view_node_next (tree_view, cursor_node);
- }
-
- gtk_tree_path_free (cursor_path);
-
- if (new_cursor_node)
- {
- cursor_path = _pspp_sheet_view_find_path (tree_view, new_cursor_node);
-
- search_first_focusable_path (tree_view, &cursor_path,
- (count != -1),
- &new_cursor_node);
-
- if (cursor_path)
- gtk_tree_path_free (cursor_path);
- }
-
- /*
- * If the list has only one item and multi-selection is set then select
- * the row (if not yet selected).
- */
- if ((tree_view->priv->selection->type == PSPP_SHEET_SELECTION_MULTIPLE ||
- tree_view->priv->selection->type == PSPP_SHEET_SELECTION_RECTANGLE) &&
- new_cursor_node < 0)
- {
- if (count == -1)
- new_cursor_node = pspp_sheet_view_node_next (tree_view, cursor_node);
- else
- new_cursor_node = pspp_sheet_view_node_prev (tree_view, cursor_node);
-
- if (new_cursor_node < 0
- && !pspp_sheet_view_node_is_selected (tree_view, cursor_node))
- {
- new_cursor_node = cursor_node;
- }
- else
- {
- new_cursor_node = -1;
- }
- }
-
- if (new_cursor_node >= 0)
- {
- cursor_path = _pspp_sheet_view_find_path (tree_view, new_cursor_node);
- pspp_sheet_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE, mode);
- gtk_tree_path_free (cursor_path);
- }
- else
- {
- pspp_sheet_view_clamp_node_visible (tree_view, cursor_node);
-
- if (!(mode & PSPP_SHEET_SELECT_MODE_EXTEND))
- {
- if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
- count < 0 ?
- GTK_DIR_UP : GTK_DIR_DOWN))
- {
- GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
-
- if (toplevel)
- gtk_widget_child_focus (toplevel,
- count < 0 ?
- GTK_DIR_TAB_BACKWARD :
- GTK_DIR_TAB_FORWARD);
-
- grab_focus = FALSE;
- }
- }
- else
- {
- gtk_widget_error_bell (GTK_WIDGET (tree_view));
- }
- }
-
- if (grab_focus)
- gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-
- return new_cursor_node >= 0;
-}
-
-static void
-pspp_sheet_view_move_cursor_page_up_down (PsppSheetView *tree_view,
- gint count,
- PsppSheetSelectMode mode)
-{
- int cursor_node = -1;
- GtkTreePath *old_cursor_path = NULL;
- GtkTreePath *cursor_path = NULL;
- int start_cursor_node = -1;
- gint y;
- gint window_y;
- gint vertical_separator;
-
- if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
- return;
-
- if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
- old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
- else
- /* This is sorta weird. Focus in should give us a cursor */
- return;
-
- gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
- _pspp_sheet_view_find_node (tree_view, old_cursor_path, &cursor_node);
-
- if (cursor_node < 0)
- {
- /* FIXME: we lost the cursor. Should we try to get one? */
- gtk_tree_path_free (old_cursor_path);
- return;
- }
-
- y = pspp_sheet_view_node_find_offset (tree_view, cursor_node);
- window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
- y += tree_view->priv->cursor_offset;
- y += count * (int)gtk_adjustment_get_page_increment (tree_view->priv->vadjustment);
- y = CLAMP (y, (gint)gtk_adjustment_get_lower (tree_view->priv->vadjustment), (gint)gtk_adjustment_get_upper (tree_view->priv->vadjustment) - vertical_separator);
-
- if (y >= tree_view->priv->height)
- y = tree_view->priv->height - 1;
-
- tree_view->priv->cursor_offset =
- pspp_sheet_view_find_offset (tree_view, y, &cursor_node);
-
- if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (tree_view))
- {
- cursor_node = pspp_sheet_view_node_next (tree_view, cursor_node);
- tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (tree_view);
- }
-
- y -= tree_view->priv->cursor_offset;
- cursor_path = _pspp_sheet_view_find_path (tree_view, cursor_node);
-
- start_cursor_node = cursor_node;
-
- if (! search_first_focusable_path (tree_view, &cursor_path,
- (count != -1),
- &cursor_node))
- {
- /* It looks like we reached the end of the view without finding
- * a focusable row. We will step backwards to find the last
- * focusable row.
- */
- cursor_node = start_cursor_node;
- cursor_path = _pspp_sheet_view_find_path (tree_view, cursor_node);
-
- search_first_focusable_path (tree_view, &cursor_path,
- (count == -1),
- &cursor_node);
- }
-
- if (!cursor_path)
- goto cleanup;
-
- /* update y */
- y = pspp_sheet_view_node_find_offset (tree_view, cursor_node);
-
- pspp_sheet_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE, mode);
-
- y -= window_y;
- pspp_sheet_view_scroll_to_point (tree_view, -1, y);
- pspp_sheet_view_clamp_node_visible (tree_view, cursor_node);
- _pspp_sheet_view_queue_draw_node (tree_view, cursor_node, NULL);
-
- if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
- gtk_widget_error_bell (GTK_WIDGET (tree_view));
-
- gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-
-cleanup:
- gtk_tree_path_free (old_cursor_path);
- gtk_tree_path_free (cursor_path);
-}
-
-static void
-pspp_sheet_view_move_cursor_left_right (PsppSheetView *tree_view,
- gint count,
- PsppSheetSelectMode mode)
-{
- int cursor_node = -1;
- GtkTreePath *cursor_path = NULL;
- PsppSheetViewColumn *column;
- GtkTreeIter iter;
- GList *list;
- gboolean found_column = FALSE;
- gboolean rtl;
-
- rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
- if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
- return;
-
- if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
- cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
- else
- return;
-
- _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node);
- if (cursor_node < 0)
- return;
- if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
- {
- gtk_tree_path_free (cursor_path);
- return;
- }
- gtk_tree_path_free (cursor_path);
-
- list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
- if (tree_view->priv->focus_column)
- {
- for (; list; list = (rtl ? list->prev : list->next))
- {
- if (list->data == tree_view->priv->focus_column)
- break;
- }
- }
-
- while (list)
- {
- gboolean left, right;
-
- column = list->data;
- if (column->visible == FALSE || column->row_head)
- goto loop_end;
-
- pspp_sheet_view_column_cell_set_cell_data (column,
- tree_view->priv->model,
- &iter);
-
- if (rtl)
- {
- right = list->prev ? TRUE : FALSE;
- left = list->next ? TRUE : FALSE;
- }
- else
- {
- left = list->prev ? TRUE : FALSE;
- right = list->next ? TRUE : FALSE;
- }
-
- if (_pspp_sheet_view_column_cell_focus (column, count, left, right))
- {
- tree_view->priv->focus_column = column;
- found_column = TRUE;
- break;
- }
- loop_end:
- if (count == 1)
- list = rtl ? list->prev : list->next;
- else
- list = rtl ? list->next : list->prev;
- }
-
- if (found_column)
- {
- _pspp_sheet_view_queue_draw_node (tree_view, cursor_node, NULL);
- g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
- gtk_widget_grab_focus (GTK_WIDGET (tree_view));
- }
- else
- {
- gtk_widget_error_bell (GTK_WIDGET (tree_view));
- }
-
- pspp_sheet_view_clamp_column_visible (tree_view,
- tree_view->priv->focus_column, TRUE);
-}
-
-static void
-pspp_sheet_view_move_cursor_line_start_end (PsppSheetView *tree_view,
- gint count,
- PsppSheetSelectMode mode)
-{
- int cursor_node = -1;
- GtkTreePath *cursor_path = NULL;
- PsppSheetViewColumn *column;
- PsppSheetViewColumn *found_column;
- GtkTreeIter iter;
- GList *list;
- gboolean rtl;
-
- rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
-
- if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
- return;
-
- if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
- cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
- else
- return;
-
- _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node);
- if (cursor_node < 0)
- return;
- if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
- {
- gtk_tree_path_free (cursor_path);
- return;
- }
- gtk_tree_path_free (cursor_path);
-
- list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
- if (tree_view->priv->focus_column)
- {
- for (; list; list = (rtl ? list->prev : list->next))
- {
- if (list->data == tree_view->priv->focus_column)
- break;
- }
- }
-
- found_column = NULL;
- while (list)
- {
- gboolean left, right;
-
- column = list->data;
- if (column->visible == FALSE || column->row_head)
- goto loop_end;
-
- pspp_sheet_view_column_cell_set_cell_data (column,
- tree_view->priv->model,
- &iter);
-
- if (rtl)
- {
- right = list->prev ? TRUE : FALSE;
- left = list->next ? TRUE : FALSE;
- }
- else
- {
- left = list->prev ? TRUE : FALSE;
- right = list->next ? TRUE : FALSE;
- }
-
- if (column->tabbable
- && _pspp_sheet_view_column_cell_focus (column, count, left, right))
- found_column = column;
-
- loop_end:
- if (count == 1)
- list = rtl ? list->prev : list->next;
- else
- list = rtl ? list->next : list->prev;
- }
-
- if (found_column)
- {
- tree_view->priv->focus_column = found_column;
- _pspp_sheet_view_queue_draw_node (tree_view, cursor_node, NULL);
- g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
- gtk_widget_grab_focus (GTK_WIDGET (tree_view));
- }
-
- pspp_sheet_view_clamp_column_visible (tree_view,
- tree_view->priv->focus_column, TRUE);
-}
-
-static gboolean
-try_move_cursor_tab (PsppSheetView *tree_view,
- gboolean start_at_focus_column,
- gint count)
-{
- PsppSheetViewColumn *column;
- GtkTreeIter iter;
- int cursor_node = -1;
- GtkTreePath *cursor_path = NULL;
- gboolean rtl;
- GList *list;
-
- if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
- cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
- else
- return TRUE;
-
- _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node);
- if (cursor_node < 0)
- return TRUE;
- if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
- {
- gtk_tree_path_free (cursor_path);
- return TRUE;
- }
- gtk_tree_path_free (cursor_path);
-
- rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
- if (start_at_focus_column)
- {
- list = (rtl
- ? g_list_last (tree_view->priv->columns)
- : g_list_first (tree_view->priv->columns));
- if (tree_view->priv->focus_column)
- {
- for (; list; list = (rtl ? list->prev : list->next))
- {
- if (list->data == tree_view->priv->focus_column)
- break;
- }
- }
- }
- else
- {
- list = (rtl ^ (count == 1)
- ? g_list_first (tree_view->priv->columns)
- : g_list_last (tree_view->priv->columns));
- }
-
- while (list)
- {
- gboolean left, right;
-
- column = list->data;
- if (column->visible == FALSE || !column->tabbable)
- goto loop_end;
-
- pspp_sheet_view_column_cell_set_cell_data (column,
- tree_view->priv->model,
- &iter);
-
- if (rtl)
- {
- right = list->prev ? TRUE : FALSE;
- left = list->next ? TRUE : FALSE;
- }
- else
- {
- left = list->prev ? TRUE : FALSE;
- right = list->next ? TRUE : FALSE;
- }
-
- if (column->tabbable
- && _pspp_sheet_view_column_cell_focus (column, count, left, right))
- {
- tree_view->priv->focus_column = column;
- _pspp_sheet_view_queue_draw_node (tree_view, cursor_node, NULL);
- g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
- gtk_widget_grab_focus (GTK_WIDGET (tree_view));
- return TRUE;
- }
- loop_end:
- if (count == 1)
- list = rtl ? list->prev : list->next;
- else
- list = rtl ? list->next : list->prev;
- }
-
- return FALSE;
-}
-
-static void
-pspp_sheet_view_move_cursor_tab (PsppSheetView *tree_view,
- gint count)
-{
- if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
- return;
-
- if (!try_move_cursor_tab (tree_view, TRUE, count))
- {
- if (pspp_sheet_view_move_cursor_up_down (tree_view, count, 0)
- && !try_move_cursor_tab (tree_view, FALSE, count))
- gtk_widget_error_bell (GTK_WIDGET (tree_view));
- }
-
- pspp_sheet_view_clamp_column_visible (tree_view,
- tree_view->priv->focus_column, TRUE);
-}
-
-static void
-pspp_sheet_view_move_cursor_start_end (PsppSheetView *tree_view,
- gint count,
- PsppSheetSelectMode mode)
-{
- int cursor_node;
- GtkTreePath *path;
- GtkTreePath *old_path;
-
- if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
- return;
-
- g_return_if_fail (tree_view->priv->row_count > 0);
-
- pspp_sheet_view_get_cursor (tree_view, &old_path, NULL);
-
- if (count == -1)
- {
- /* Now go forward to find the first focusable row. */
- path = _pspp_sheet_view_find_path (tree_view, 0);
- search_first_focusable_path (tree_view, &path,
- TRUE, &cursor_node);
- }
- else
- {
- /* Now go backwards to find last focusable row. */
- path = _pspp_sheet_view_find_path (tree_view, tree_view->priv->row_count - 1);
- search_first_focusable_path (tree_view, &path,
- FALSE, &cursor_node);
- }
-
- if (!path)
- goto cleanup;
-
- if (gtk_tree_path_compare (old_path, path))
- {
- pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE, mode);
- gtk_widget_grab_focus (GTK_WIDGET (tree_view));
- }
- else
- {
- gtk_widget_error_bell (GTK_WIDGET (tree_view));
- }
-
-cleanup:
- gtk_tree_path_free (old_path);
- gtk_tree_path_free (path);
-}
-
-static gboolean
-pspp_sheet_view_real_select_all (PsppSheetView *tree_view)
-{
- if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
- return FALSE;
-
- if (tree_view->priv->selection->type != PSPP_SHEET_SELECTION_MULTIPLE &&
- tree_view->priv->selection->type != PSPP_SHEET_SELECTION_RECTANGLE)
- return FALSE;
-
- pspp_sheet_selection_select_all (tree_view->priv->selection);
-
- return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_real_unselect_all (PsppSheetView *tree_view)
-{
- if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
- return FALSE;
-
- if (tree_view->priv->selection->type != PSPP_SHEET_SELECTION_MULTIPLE &&
- tree_view->priv->selection->type != PSPP_SHEET_SELECTION_RECTANGLE)
- return FALSE;
-
- pspp_sheet_selection_unselect_all (tree_view->priv->selection);
-
- return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_real_select_cursor_row (PsppSheetView *tree_view,
- gboolean start_editing,
- PsppSheetSelectMode mode)
-{
- int new_node = -1;
- int cursor_node = -1;
- GtkTreePath *cursor_path = NULL;
-
- if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
- return FALSE;
-
- if (tree_view->priv->cursor)
- cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-
- if (cursor_path == NULL)
- return FALSE;
-
- _pspp_sheet_view_find_node (tree_view, cursor_path,
- &cursor_node);
-
- if (cursor_node < 0)
- {
- gtk_tree_path_free (cursor_path);
- return FALSE;
- }
-
- if (!(mode & PSPP_SHEET_SELECT_MODE_EXTEND) && start_editing &&
- tree_view->priv->focus_column)
- {
- if (pspp_sheet_view_start_editing (tree_view, cursor_path))
- {
- gtk_tree_path_free (cursor_path);
- return TRUE;
- }
- }
-
- _pspp_sheet_selection_internal_select_node (tree_view->priv->selection,
- cursor_node,
- cursor_path,
- mode,
- FALSE);
-
- /* We bail out if the original (tree, node) don't exist anymore after
- * handling the selection-changed callback. We do return TRUE because
- * the key press has been handled at this point.
- */
- _pspp_sheet_view_find_node (tree_view, cursor_path, &new_node);
-
- if (cursor_node != new_node)
- return FALSE;
-
- pspp_sheet_view_clamp_node_visible (tree_view, cursor_node);
-
- gtk_widget_grab_focus (GTK_WIDGET (tree_view));
- _pspp_sheet_view_queue_draw_node (tree_view, cursor_node, NULL);
-
- if (!(mode & PSPP_SHEET_SELECT_MODE_EXTEND))
- pspp_sheet_view_row_activated (tree_view, cursor_path,
- tree_view->priv->focus_column);
-
- gtk_tree_path_free (cursor_path);
-
- return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_real_toggle_cursor_row (PsppSheetView *tree_view)
-{
- int new_node = -1;
- int cursor_node = -1;
- GtkTreePath *cursor_path = NULL;
-
- if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
- return FALSE;
-
- cursor_path = NULL;
- if (tree_view->priv->cursor)
- cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-
- if (cursor_path == NULL)
- return FALSE;
-
- _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node);
- if (cursor_node < 0)
- {
- gtk_tree_path_free (cursor_path);
- return FALSE;
- }
-
- _pspp_sheet_selection_internal_select_node (tree_view->priv->selection,
- cursor_node,
- cursor_path,
- PSPP_SHEET_SELECT_MODE_TOGGLE,
- FALSE);
-
- /* We bail out if the original (tree, node) don't exist anymore after
- * handling the selection-changed callback. We do return TRUE because
- * the key press has been handled at this point.
- */
- _pspp_sheet_view_find_node (tree_view, cursor_path, &new_node);
-
- if (cursor_node != new_node)
- return FALSE;
-
- pspp_sheet_view_clamp_node_visible (tree_view, cursor_node);
-
- gtk_widget_grab_focus (GTK_WIDGET (tree_view));
- pspp_sheet_view_queue_draw_path (tree_view, cursor_path, NULL);
- gtk_tree_path_free (cursor_path);
-
- return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_search_entry_flush_timeout (PsppSheetView *tree_view)
-{
- pspp_sheet_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
- tree_view->priv->typeselect_flush_timeout = 0;
-
- return FALSE;
-}
-
-/* Cut and paste from gtkwindow.c */
-static void
-send_focus_change (GtkWidget *widget,
- gboolean in)
-{
- GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
-
- fevent->focus_change.type = GDK_FOCUS_CHANGE;
- fevent->focus_change.window = g_object_ref (gtk_widget_get_window (widget));
- fevent->focus_change.in = in;
-
- gtk_widget_send_focus_change (widget, fevent);
- gdk_event_free (fevent);
-}
-
-static void
-pspp_sheet_view_ensure_interactive_directory (PsppSheetView *tree_view)
-{
- GtkWidget *frame, *vbox, *toplevel;
- GdkScreen *screen;
-
- if (tree_view->priv->search_custom_entry_set)
- return;
-
- toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
- screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
-
- if (tree_view->priv->search_window != NULL)
- {
- if (gtk_window_get_group (GTK_WINDOW (toplevel)))
- gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
- GTK_WINDOW (tree_view->priv->search_window));
- else if (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)))
- gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
- GTK_WINDOW (tree_view->priv->search_window));
- gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
- return;
- }
-
- tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
- gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
-
- if (gtk_window_get_group (GTK_WINDOW (toplevel)))
- gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
- GTK_WINDOW (tree_view->priv->search_window));
-
- gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
- GDK_WINDOW_TYPE_HINT_UTILITY);
- gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
- g_signal_connect (tree_view->priv->search_window, "delete-event",
- G_CALLBACK (pspp_sheet_view_search_delete_event),
- tree_view);
- g_signal_connect (tree_view->priv->search_window, "key-press-event",
- G_CALLBACK (pspp_sheet_view_search_key_press_event),
- tree_view);
- g_signal_connect (tree_view->priv->search_window, "button-press-event",
- G_CALLBACK (pspp_sheet_view_search_button_press_event),
- tree_view);
- g_signal_connect (tree_view->priv->search_window, "scroll-event",
- G_CALLBACK (pspp_sheet_view_search_scroll_event),
- tree_view);
-
- frame = gtk_frame_new (NULL);
- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
- gtk_widget_show (frame);
- gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
-
- vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
- gtk_widget_show (vbox);
- gtk_container_add (GTK_CONTAINER (frame), vbox);
- gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
-
- /* add entry */
- tree_view->priv->search_entry = gtk_entry_new ();
- gtk_widget_show (tree_view->priv->search_entry);
- g_signal_connect (tree_view->priv->search_entry, "populate-popup",
- G_CALLBACK (pspp_sheet_view_search_disable_popdown),
- tree_view);
- g_signal_connect (tree_view->priv->search_entry,
- "activate", G_CALLBACK (pspp_sheet_view_search_activate),
- tree_view);
-
- gtk_container_add (GTK_CONTAINER (vbox),
- tree_view->priv->search_entry);
-
- gtk_widget_realize (tree_view->priv->search_entry);
-}
-
-/* Pops up the interactive search entry. If keybinding is TRUE then the user
- * started this by typing the start_interactive_search keybinding. Otherwise, it came from
- */
-static gboolean
-pspp_sheet_view_real_start_interactive_search (PsppSheetView *tree_view,
- gboolean keybinding)
-{
- /* We only start interactive search if we have focus or the columns
- * have focus. If one of our children have focus, we don't want to
- * start the search.
- */
- GList *list;
- gboolean found_focus = FALSE;
- GtkWidgetClass *entry_parent_class;
-
- if (!tree_view->priv->enable_search && !keybinding)
- return FALSE;
-
- if (tree_view->priv->search_custom_entry_set)
- return FALSE;
-
- if (tree_view->priv->search_window != NULL &&
- gtk_widget_get_visible (tree_view->priv->search_window))
- return TRUE;
-
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- PsppSheetViewColumn *column;
-
- column = list->data;
- if (! column->visible)
- continue;
-
- if (column->button && gtk_widget_has_focus (column->button))
- {
- found_focus = TRUE;
- break;
- }
- }
-
- if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
- found_focus = TRUE;
-
- if (!found_focus)
- return FALSE;
-
- if (tree_view->priv->search_column < 0)
- return FALSE;
-
- pspp_sheet_view_ensure_interactive_directory (tree_view);
-
- if (keybinding)
- gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
-
- /* done, show it */
- tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
- gtk_widget_show (tree_view->priv->search_window);
- if (tree_view->priv->search_entry_changed_id == 0)
- {
- tree_view->priv->search_entry_changed_id =
- g_signal_connect (tree_view->priv->search_entry, "changed",
- G_CALLBACK (pspp_sheet_view_search_init),
- tree_view);
- }
-
- tree_view->priv->typeselect_flush_timeout =
- gdk_threads_add_timeout (PSPP_SHEET_VIEW_SEARCH_DIALOG_TIMEOUT,
- (GSourceFunc) pspp_sheet_view_search_entry_flush_timeout,
- tree_view);
-
- /* Grab focus will select all the text. We don't want that to happen, so we
- * call the parent instance and bypass the selection change. This is probably
- * really non-kosher. */
- entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
- (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
-
- /* send focus-in event */
- send_focus_change (tree_view->priv->search_entry, TRUE);
-
- /* search first matching iter */
- pspp_sheet_view_search_init (tree_view->priv->search_entry, tree_view);
-
- return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_start_interactive_search (PsppSheetView *tree_view)
-{
- return pspp_sheet_view_real_start_interactive_search (tree_view, TRUE);
-}
-
-/* this function returns the new width of the column being resized given
- * the column and x position of the cursor; the x cursor position is passed
- * in as a pointer and automagicly corrected if it's beyond min/max limits
- */
-static gint
-pspp_sheet_view_new_column_width (PsppSheetView *tree_view,
- gint i,
- gint *x)
-{
- PsppSheetViewColumn *column;
- gint width;
- gboolean rtl;
-
- /* first translate the x position from gtk_widget_get_window (widget)
- * to clist->clist_window
- */
- rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
- column = g_list_nth (tree_view->priv->columns, i)->data;
- width = rtl ? (column->allocation.x + column->allocation.width - *x) : (*x - column->allocation.x);
-
- /* Clamp down the value */
- if (column->min_width == -1)
- width = MAX (column->button_request, width);
- else
- width = MAX (column->min_width, width);
- if (column->max_width != -1)
- width = MIN (width, column->max_width);
-
- *x = rtl ? (column->allocation.x + column->allocation.width - width) : (column->allocation.x + width);
-
- return width;
-}
-
-void
-pspp_sheet_view_column_update_button (PsppSheetViewColumn *tree_column);
-
-/* Callbacks */
-static void
-pspp_sheet_view_adjustment_changed (GtkAdjustment *adjustment,
- PsppSheetView *tree_view)
-{
- if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
- {
- gint dy;
-
- gdk_window_move (tree_view->priv->bin_window,
- - gtk_adjustment_get_value (tree_view->priv->hadjustment),
- TREE_VIEW_HEADER_HEIGHT (tree_view));
- gdk_window_move (tree_view->priv->header_window,
- - gtk_adjustment_get_value (tree_view->priv->hadjustment),
- 0);
- dy = tree_view->priv->dy - (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
-
- gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
-
- if (dy != 0)
- {
- /* update our dy and top_row */
- tree_view->priv->dy = (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
-
- update_prelight (tree_view,
- tree_view->priv->event_last_x,
- tree_view->priv->event_last_y);
-
- if (!tree_view->priv->in_top_row_to_dy)
- pspp_sheet_view_dy_to_top_row (tree_view);
- }
-
- update_childrens_allocation(tree_view);
- }
-}
-
-/* Public methods
- */
-
-/**
- * pspp_sheet_view_new:
- *
- * Creates a new #PsppSheetView widget.
- *
- * Return value: A newly created #PsppSheetView widget.
- **/
-GtkWidget *
-pspp_sheet_view_new (void)
-{
- return g_object_new (PSPP_TYPE_SHEET_VIEW, NULL);
-}
-
-/**
- * pspp_sheet_view_new_with_model:
- * @model: the model.
- *
- * Creates a new #PsppSheetView widget with the model initialized to @model.
- *
- * Return value: A newly created #PsppSheetView widget.
- **/
-GtkWidget *
-pspp_sheet_view_new_with_model (GtkTreeModel *model)
-{
- return g_object_new (PSPP_TYPE_SHEET_VIEW, "model", model, NULL);
-}
-
-/* Public Accessors
- */
-
-/**
- * pspp_sheet_view_get_model:
- * @tree_view: a #PsppSheetView
- *
- * Returns the model the #PsppSheetView is based on. Returns %NULL if the
- * model is unset.
- *
- * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
- **/
-GtkTreeModel *
-pspp_sheet_view_get_model (PsppSheetView *tree_view)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
- return tree_view->priv->model;
-}
-
-/**
- * pspp_sheet_view_set_model:
- * @tree_view: A #GtkTreeNode.
- * @model: (allow-none): The model.
- *
- * Sets the model for a #PsppSheetView. If the @tree_view already has a model
- * set, it will remove it before setting the new model. If @model is %NULL,
- * then it will unset the old model.
- **/
-void
-pspp_sheet_view_set_model (PsppSheetView *tree_view,
- GtkTreeModel *model)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
- g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
-
- if (model == tree_view->priv->model)
- return;
-
- if (tree_view->priv->scroll_to_path)
- {
- gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
- tree_view->priv->scroll_to_path = NULL;
- }
-
- if (tree_view->priv->model)
- {
- GList *tmplist = tree_view->priv->columns;
-
- if (tree_view->priv->selected)
- range_tower_set0 (tree_view->priv->selected, 0, ULONG_MAX);
- pspp_sheet_view_stop_editing (tree_view, TRUE);
-
- g_signal_handlers_disconnect_by_func (tree_view->priv->model,
- pspp_sheet_view_row_changed,
- tree_view);
- g_signal_handlers_disconnect_by_func (tree_view->priv->model,
- pspp_sheet_view_row_inserted,
- tree_view);
- g_signal_handlers_disconnect_by_func (tree_view->priv->model,
- pspp_sheet_view_row_deleted,
- tree_view);
- g_signal_handlers_disconnect_by_func (tree_view->priv->model,
- pspp_sheet_view_rows_reordered,
- tree_view);
-
- for (; tmplist; tmplist = tmplist->next)
- _pspp_sheet_view_column_unset_model (tmplist->data,
- tree_view->priv->model);
-
- tree_view->priv->prelight_node = -1;
-
- gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
- tree_view->priv->drag_dest_row = NULL;
- gtk_tree_row_reference_free (tree_view->priv->cursor);
- tree_view->priv->cursor = NULL;
- gtk_tree_row_reference_free (tree_view->priv->anchor);
- tree_view->priv->anchor = NULL;
- gtk_tree_row_reference_free (tree_view->priv->top_row);
- tree_view->priv->top_row = NULL;
- gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
- tree_view->priv->scroll_to_path = NULL;
-
- tree_view->priv->scroll_to_column = NULL;
-
- g_object_unref (tree_view->priv->model);
-
- tree_view->priv->search_column = -1;
- tree_view->priv->fixed_height = -1;
- tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
- tree_view->priv->last_button_x = -1;
- tree_view->priv->last_button_y = -1;
- }
-
- tree_view->priv->model = model;
-
- if (tree_view->priv->model)
- {
- gint i;
-
- if (tree_view->priv->search_column == -1)
- {
- for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
- {
- GType type = gtk_tree_model_get_column_type (model, i);
-
- if (g_value_type_transformable (type, G_TYPE_STRING))
- {
- tree_view->priv->search_column = i;
- break;
- }
- }
- }
-
- g_object_ref (tree_view->priv->model);
- g_signal_connect (tree_view->priv->model,
- "row-changed",
- G_CALLBACK (pspp_sheet_view_row_changed),
- tree_view);
- g_signal_connect (tree_view->priv->model,
- "row-inserted",
- G_CALLBACK (pspp_sheet_view_row_inserted),
- tree_view);
- g_signal_connect (tree_view->priv->model,
- "row-deleted",
- G_CALLBACK (pspp_sheet_view_row_deleted),
- tree_view);
- g_signal_connect (tree_view->priv->model,
- "rows-reordered",
- G_CALLBACK (pspp_sheet_view_rows_reordered),
- tree_view);
-
- tree_view->priv->row_count = gtk_tree_model_iter_n_children (tree_view->priv->model, NULL);
-
- /* FIXME: do I need to do this? pspp_sheet_view_create_buttons (tree_view); */
- install_presize_handler (tree_view);
- }
-
- g_object_notify (G_OBJECT (tree_view), "model");
-
- if (tree_view->priv->selection)
- _pspp_sheet_selection_emit_changed (tree_view->priv->selection);
-
- if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
- gtk_widget_queue_resize (GTK_WIDGET (tree_view));
-}
-
-/**
- * pspp_sheet_view_get_selection:
- * @tree_view: A #PsppSheetView.
- *
- * Gets the #PsppSheetSelection associated with @tree_view.
- *
- * Return value: A #PsppSheetSelection object.
- **/
-PsppSheetSelection *
-pspp_sheet_view_get_selection (PsppSheetView *tree_view)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
- return tree_view->priv->selection;
-}
-
-/**
- * pspp_sheet_view_get_hadjustment:
- * @tree_view: A #PsppSheetView
- *
- * Gets the #GtkAdjustment currently being used for the horizontal aspect.
- *
- * Return value: A #GtkAdjustment object, or %NULL if none is currently being
- * used.
- **/
-GtkAdjustment *
-pspp_sheet_view_get_hadjustment (PsppSheetView *tree_view)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
- return pspp_sheet_view_do_get_hadjustment (tree_view);
-}
-
-static GtkAdjustment *
-pspp_sheet_view_do_get_hadjustment (PsppSheetView *tree_view)
-{
- return tree_view->priv->hadjustment;
-}
-
-/**
- * pspp_sheet_view_set_hadjustment:
- * @tree_view: A #PsppSheetView
- * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
- *
- * Sets the #GtkAdjustment for the current horizontal aspect.
- **/
-void
-pspp_sheet_view_set_hadjustment (PsppSheetView *tree_view,
- GtkAdjustment *adjustment)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- pspp_sheet_view_set_adjustments (tree_view,
- adjustment,
- tree_view->priv->vadjustment);
-
- g_object_notify (G_OBJECT (tree_view), "hadjustment");
-}
-
-static void
-pspp_sheet_view_do_set_hadjustment (PsppSheetView *tree_view,
- GtkAdjustment *adjustment)
-{
- PsppSheetViewPrivate *priv = tree_view->priv;
-
- if (adjustment && priv->hadjustment == adjustment)
- return;
-
- if (priv->hadjustment != NULL)
- {
- g_signal_handlers_disconnect_by_func (priv->hadjustment,
- pspp_sheet_view_adjustment_changed,
- tree_view);
- g_object_unref (priv->hadjustment);
- }
-
- if (adjustment == NULL)
- adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
- 0.0, 0.0, 0.0);
-
- g_signal_connect (adjustment, "value-changed",
- G_CALLBACK (pspp_sheet_view_adjustment_changed), tree_view);
- priv->hadjustment = g_object_ref_sink (adjustment);
- /* FIXME: Adjustment should probably be populated here with fresh values, but
- * internal details are too complicated for me to decipher right now.
- */
- pspp_sheet_view_adjustment_changed (NULL, tree_view);
-
- g_object_notify (G_OBJECT (tree_view), "hadjustment");
-}
-
-/**
- * pspp_sheet_view_get_vadjustment:
- * @tree_view: A #PsppSheetView
- *
- * Gets the #GtkAdjustment currently being used for the vertical aspect.
- *
- * Return value: (transfer none): A #GtkAdjustment object, or %NULL
- * if none is currently being used.
- *
- * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
- **/
-GtkAdjustment *
-pspp_sheet_view_get_vadjustment (PsppSheetView *tree_view)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
- return pspp_sheet_view_do_get_vadjustment (tree_view);
-}
-
-static GtkAdjustment *
-pspp_sheet_view_do_get_vadjustment (PsppSheetView *tree_view)
-{
- return tree_view->priv->vadjustment;
-}
-
-/**
- * pspp_sheet_view_set_vadjustment:
- * @tree_view: A #PsppSheetView
- * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
- *
- * Sets the #GtkAdjustment for the current vertical aspect.
- *
- * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
- **/
-void
-pspp_sheet_view_set_vadjustment (PsppSheetView *tree_view,
- GtkAdjustment *adjustment)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
- g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
-
- pspp_sheet_view_do_set_vadjustment (tree_view, adjustment);
-}
-
-static void
-pspp_sheet_view_do_set_vadjustment (PsppSheetView *tree_view,
- GtkAdjustment *adjustment)
-{
- PsppSheetViewPrivate *priv = tree_view->priv;
-
- if (adjustment && priv->vadjustment == adjustment)
- return;
-
- if (priv->vadjustment != NULL)
- {
- g_signal_handlers_disconnect_by_func (priv->vadjustment,
- pspp_sheet_view_adjustment_changed,
- tree_view);
- g_object_unref (priv->vadjustment);
- }
-
- if (adjustment == NULL)
- adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
- 0.0, 0.0, 0.0);
-
- g_signal_connect (adjustment, "value-changed",
- G_CALLBACK (pspp_sheet_view_adjustment_changed), tree_view);
- priv->vadjustment = g_object_ref_sink (adjustment);
- /* FIXME: Adjustment should probably be populated here with fresh values, but
- * internal details are too complicated for me to decipher right now.
- */
- pspp_sheet_view_adjustment_changed (NULL, tree_view);
- g_object_notify (G_OBJECT (tree_view), "vadjustment");
-}
-
-/* Column and header operations */
-
-/**
- * pspp_sheet_view_get_headers_visible:
- * @tree_view: A #PsppSheetView.
- *
- * Returns %TRUE if the headers on the @tree_view are visible.
- *
- * Return value: Whether the headers are visible or not.
- **/
-gboolean
-pspp_sheet_view_get_headers_visible (PsppSheetView *tree_view)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
-
- return PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_HEADERS_VISIBLE);
-}
-
-/**
- * pspp_sheet_view_set_headers_visible:
- * @tree_view: A #PsppSheetView.
- * @headers_visible: %TRUE if the headers are visible
- *
- * Sets the visibility state of the headers.
- **/
-void
-pspp_sheet_view_set_headers_visible (PsppSheetView *tree_view,
- gboolean headers_visible)
-{
- gint x, y;
- GList *list;
- PsppSheetViewColumn *column;
- GtkAllocation allocation;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
-
- headers_visible = !! headers_visible;
-
- if (PSPP_SHEET_VIEW_FLAG_SET (tree_view, PSPP_SHEET_VIEW_HEADERS_VISIBLE) == headers_visible)
- return;
-
- if (headers_visible)
- PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_HEADERS_VISIBLE);
- else
- PSPP_SHEET_VIEW_UNSET_FLAG (tree_view, PSPP_SHEET_VIEW_HEADERS_VISIBLE);
-
- if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
- {
- gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
- if (headers_visible)
- {
- gdk_window_move_resize (tree_view->priv->bin_window, x, y + TREE_VIEW_HEADER_HEIGHT (tree_view),
- tree_view->priv->width, allocation.height - + TREE_VIEW_HEADER_HEIGHT (tree_view));
-
- if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
- pspp_sheet_view_map_buttons (tree_view);
- }
- else
- {
- gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
-
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- column = list->data;
- if (column->button)
- gtk_widget_unmap (column->button);
- }
- gdk_window_hide (tree_view->priv->header_window);
- }
- }
-
- gtk_adjustment_set_page_size (tree_view->priv->vadjustment, allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view));
- gtk_adjustment_set_page_increment (tree_view->priv->vadjustment, (allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2);
- gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
- gtk_adjustment_set_upper (tree_view->priv->vadjustment, tree_view->priv->height);
- gtk_adjustment_changed (tree_view->priv->vadjustment);
-
- gtk_widget_queue_resize (GTK_WIDGET (tree_view));
-
- g_object_notify (G_OBJECT (tree_view), "headers-visible");
-}
-
-/**
- * pspp_sheet_view_columns_autosize:
- * @tree_view: A #PsppSheetView.
- *
- * Resizes all columns to their optimal width. Only works after the
- * treeview has been realized.
- **/
-void
-pspp_sheet_view_columns_autosize (PsppSheetView *tree_view)
-{
- gboolean dirty = FALSE;
- GList *list;
- PsppSheetViewColumn *column;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- column = list->data;
- _pspp_sheet_view_column_cell_set_dirty (column);
- dirty = TRUE;
- }
-
- if (dirty)
- gtk_widget_queue_resize (GTK_WIDGET (tree_view));
-}
-
-/**
- * pspp_sheet_view_set_headers_clickable:
- * @tree_view: A #PsppSheetView.
- * @setting: %TRUE if the columns are clickable.
- *
- * Allow the column title buttons to be clicked.
- **/
-void
-pspp_sheet_view_set_headers_clickable (PsppSheetView *tree_view,
- gboolean setting)
-{
- GList *list;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- for (list = tree_view->priv->columns; list; list = list->next)
- pspp_sheet_view_column_set_clickable (PSPP_SHEET_VIEW_COLUMN (list->data), setting);
-
- g_object_notify (G_OBJECT (tree_view), "headers-clickable");
-}
-
-
-/**
- * pspp_sheet_view_get_headers_clickable:
- * @tree_view: A #PsppSheetView.
- *
- * Returns whether all header columns are clickable.
- *
- * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
- *
- * Since: 2.10
- **/
-gboolean
-pspp_sheet_view_get_headers_clickable (PsppSheetView *tree_view)
-{
- GList *list;
-
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
-
- for (list = tree_view->priv->columns; list; list = list->next)
- if (!PSPP_SHEET_VIEW_COLUMN (list->data)->clickable)
- return FALSE;
-
- return TRUE;
-}
-
-/**
- * pspp_sheet_view_set_rules_hint
- * @tree_view: a #PsppSheetView
- * @setting: %TRUE if the tree requires reading across rows
- *
- * This function tells GTK+ that the user interface for your
- * application requires users to read across tree rows and associate
- * cells with one another. By default, GTK+ will then render the tree
- * with alternating row colors. Do <emphasis>not</emphasis> use it
- * just because you prefer the appearance of the ruled tree; that's a
- * question for the theme. Some themes will draw tree rows in
- * alternating colors even when rules are turned off, and users who
- * prefer that appearance all the time can choose those themes. You
- * should call this function only as a <emphasis>semantic</emphasis>
- * hint to the theme engine that your tree makes alternating colors
- * useful from a functional standpoint (since it has lots of columns,
- * generally).
- *
- **/
-void
-pspp_sheet_view_set_rules_hint (PsppSheetView *tree_view,
- gboolean setting)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- setting = setting != FALSE;
-
- if (tree_view->priv->has_rules != setting)
- {
- tree_view->priv->has_rules = setting;
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
- }
-
- g_object_notify (G_OBJECT (tree_view), "rules-hint");
-}
-
-/**
- * pspp_sheet_view_get_rules_hint
- * @tree_view: a #PsppSheetView
- *
- * Gets the setting set by pspp_sheet_view_set_rules_hint().
- *
- * Return value: %TRUE if rules are useful for the user of this tree
- **/
-gboolean
-pspp_sheet_view_get_rules_hint (PsppSheetView *tree_view)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
-
- return tree_view->priv->has_rules;
-}
-
-/* Public Column functions
- */
-
-/**
- * pspp_sheet_view_append_column:
- * @tree_view: A #PsppSheetView.
- * @column: The #PsppSheetViewColumn to add.
- *
- * Appends @column to the list of columns.
- *
- * Return value: The number of columns in @tree_view after appending.
- **/
-gint
-pspp_sheet_view_append_column (PsppSheetView *tree_view,
- PsppSheetViewColumn *column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), -1);
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column), -1);
- g_return_val_if_fail (column->tree_view == NULL, -1);
-
- return pspp_sheet_view_insert_column (tree_view, column, -1);
-}
-
-
-/**
- * pspp_sheet_view_remove_column:
- * @tree_view: A #PsppSheetView.
- * @column: The #PsppSheetViewColumn to remove.
- *
- * Removes @column from @tree_view.
- *
- * Return value: The number of columns in @tree_view after removing.
- **/
-gint
-pspp_sheet_view_remove_column (PsppSheetView *tree_view,
- PsppSheetViewColumn *column)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), -1);
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column), -1);
- g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
-
- if (tree_view->priv->focus_column == column)
- tree_view->priv->focus_column = NULL;
-
- if (tree_view->priv->edited_column == column)
- {
- pspp_sheet_view_stop_editing (tree_view, TRUE);
-
- /* no need to, but just to be sure ... */
- tree_view->priv->edited_column = NULL;
- }
-
- _pspp_sheet_view_column_unset_tree_view (column);
-
- tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
- tree_view->priv->n_columns--;
-
- if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
- {
- GList *list;
-
- _pspp_sheet_view_column_unrealize_button (column);
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- PsppSheetViewColumn *tmp_column;
-
- tmp_column = PSPP_SHEET_VIEW_COLUMN (list->data);
- if (tmp_column->visible)
- _pspp_sheet_view_column_cell_set_dirty (tmp_column);
- }
-
- if (tree_view->priv->n_columns == 0 &&
- pspp_sheet_view_get_headers_visible (tree_view) &&
- tree_view->priv->header_window)
- gdk_window_hide (tree_view->priv->header_window);
-
- gtk_widget_queue_resize (GTK_WIDGET (tree_view));
- }
-
- g_object_unref (column);
- g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
-
- return tree_view->priv->n_columns;
-}
-
-/**
- * pspp_sheet_view_insert_column:
- * @tree_view: A #PsppSheetView.
- * @column: The #PsppSheetViewColumn to be inserted.
- * @position: The position to insert @column in.
- *
- * This inserts the @column into the @tree_view at @position. If @position is
- * -1, then the column is inserted at the end.
- *
- * Return value: The number of columns in @tree_view after insertion.
- **/
-gint
-pspp_sheet_view_insert_column (PsppSheetView *tree_view,
- PsppSheetViewColumn *column,
- gint position)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), -1);
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW_COLUMN (column), -1);
- g_return_val_if_fail (column->tree_view == NULL, -1);
-
- g_object_ref_sink (column);
-
- if (tree_view->priv->n_columns == 0 &&
- gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
- pspp_sheet_view_get_headers_visible (tree_view))
- {
- gdk_window_show (tree_view->priv->header_window);
- }
-
- tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
- column, position);
- tree_view->priv->n_columns++;
-
- _pspp_sheet_view_column_set_tree_view (column, tree_view);
-
- if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
- {
- GList *list;
-
- _pspp_sheet_view_column_realize_button (column);
-
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- column = PSPP_SHEET_VIEW_COLUMN (list->data);
- if (column->visible)
- _pspp_sheet_view_column_cell_set_dirty (column);
- }
- gtk_widget_queue_resize (GTK_WIDGET (tree_view));
- }
-
- g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
-
- return tree_view->priv->n_columns;
-}
-
-/**
- * pspp_sheet_view_insert_column_with_attributes:
- * @tree_view: A #PsppSheetView
- * @position: The position to insert the new column in.
- * @title: The title to set the header to.
- * @cell: The #GtkCellRenderer.
- * @Varargs: A %NULL-terminated list of attributes.
- *
- * Creates a new #PsppSheetViewColumn and inserts it into the @tree_view at
- * @position. If @position is -1, then the newly created column is inserted at
- * the end. The column is initialized with the attributes given.
- *
- * Return value: The number of columns in @tree_view after insertion.
- **/
-gint
-pspp_sheet_view_insert_column_with_attributes (PsppSheetView *tree_view,
- gint position,
- const gchar *title,
- GtkCellRenderer *cell,
- ...)
-{
- PsppSheetViewColumn *column;
- gchar *attribute;
- va_list args;
- gint column_id;
-
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), -1);
-
- column = pspp_sheet_view_column_new ();
- pspp_sheet_view_column_set_title (column, title);
- pspp_sheet_view_column_pack_start (column, cell, TRUE);
-
- va_start (args, cell);
-
- attribute = va_arg (args, gchar *);
-
- while (attribute != NULL)
- {
- column_id = va_arg (args, gint);
- pspp_sheet_view_column_add_attribute (column, cell, attribute, column_id);
- attribute = va_arg (args, gchar *);
- }
-
- va_end (args);
-
- pspp_sheet_view_insert_column (tree_view, column, position);
-
- return tree_view->priv->n_columns;
-}
-
-/**
- * pspp_sheet_view_insert_column_with_data_func:
- * @tree_view: a #PsppSheetView
- * @position: Position to insert, -1 for append
- * @title: column title
- * @cell: cell renderer for column
- * @func: function to set attributes of cell renderer
- * @data: data for @func
- * @dnotify: destroy notifier for @data
- *
- * Convenience function that inserts a new column into the #PsppSheetView
- * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
- * attributes (normally using data from the model). See also
- * pspp_sheet_view_column_set_cell_data_func(), pspp_sheet_view_column_pack_start().
- *
- * Return value: number of columns in the tree view post-insert
- **/
-gint
-pspp_sheet_view_insert_column_with_data_func (PsppSheetView *tree_view,
- gint position,
- const gchar *title,
- GtkCellRenderer *cell,
- PsppSheetCellDataFunc func,
- gpointer data,
- GDestroyNotify dnotify)
-{
- PsppSheetViewColumn *column;
-
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), -1);
-
- column = pspp_sheet_view_column_new ();
- pspp_sheet_view_column_set_title (column, title);
- pspp_sheet_view_column_pack_start (column, cell, TRUE);
- pspp_sheet_view_column_set_cell_data_func (column, cell, func, data, dnotify);
-
- pspp_sheet_view_insert_column (tree_view, column, position);
-
- return tree_view->priv->n_columns;
-}
-
-/**
- * pspp_sheet_view_get_column:
- * @tree_view: A #PsppSheetView.
- * @n: The position of the column, counting from 0.
- *
- * Gets the #PsppSheetViewColumn at the given position in the #tree_view.
- *
- * Return value: The #PsppSheetViewColumn, or %NULL if the position is outside the
- * range of columns.
- **/
-PsppSheetViewColumn *
-pspp_sheet_view_get_column (PsppSheetView *tree_view,
- gint n)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
- if (n < 0 || n >= tree_view->priv->n_columns)
- return NULL;
-
- if (tree_view->priv->columns == NULL)
- return NULL;
-
- return PSPP_SHEET_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
-}
-
-/**
- * pspp_sheet_view_get_columns:
- * @tree_view: A #PsppSheetView
- *
- * Returns a #GList of all the #PsppSheetViewColumn s currently in @tree_view.
- * The returned list must be freed with g_list_free ().
- *
- * Return value: (element-type PsppSheetViewColumn) (transfer container): A list of #PsppSheetViewColumn s
- **/
-GList *
-pspp_sheet_view_get_columns (PsppSheetView *tree_view)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
- return g_list_copy (tree_view->priv->columns);
-}
-
-/**
- * pspp_sheet_view_move_column_after:
- * @tree_view: A #PsppSheetView
- * @column: The #PsppSheetViewColumn to be moved.
- * @base_column: (allow-none): The #PsppSheetViewColumn to be moved relative to, or %NULL.
- *
- * Moves @column to be after to @base_column. If @base_column is %NULL, then
- * @column is placed in the first position.
- **/
-void
-pspp_sheet_view_move_column_after (PsppSheetView *tree_view,
- PsppSheetViewColumn *column,
- PsppSheetViewColumn *base_column)
-{
- GList *column_list_el, *base_el = NULL;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- column_list_el = g_list_find (tree_view->priv->columns, column);
- g_return_if_fail (column_list_el != NULL);
-
- if (base_column)
- {
- base_el = g_list_find (tree_view->priv->columns, base_column);
- g_return_if_fail (base_el != NULL);
- }
-
- if (column_list_el->prev == base_el)
- return;
-
- tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
- if (base_el == NULL)
- {
- column_list_el->prev = NULL;
- column_list_el->next = tree_view->priv->columns;
- if (column_list_el->next)
- column_list_el->next->prev = column_list_el;
- tree_view->priv->columns = column_list_el;
- }
- else
- {
- column_list_el->prev = base_el;
- column_list_el->next = base_el->next;
- if (column_list_el->next)
- column_list_el->next->prev = column_list_el;
- base_el->next = column_list_el;
- }
-
- if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
- {
- gtk_widget_queue_resize (GTK_WIDGET (tree_view));
- pspp_sheet_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
- }
-
- g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
-}
-
-/**
- * pspp_sheet_view_set_column_drag_function:
- * @tree_view: A #PsppSheetView.
- * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
- * @user_data: (allow-none): User data to be passed to @func, or %NULL
- * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
- *
- * Sets a user function for determining where a column may be dropped when
- * dragged. This function is called on every column pair in turn at the
- * beginning of a column drag to determine where a drop can take place. The
- * arguments passed to @func are: the @tree_view, the #PsppSheetViewColumn being
- * dragged, the two #PsppSheetViewColumn s determining the drop spot, and
- * @user_data. If either of the #PsppSheetViewColumn arguments for the drop spot
- * are %NULL, then they indicate an edge. If @func is set to be %NULL, then
- * @tree_view reverts to the default behavior of allowing all columns to be
- * dropped everywhere.
- **/
-void
-pspp_sheet_view_set_column_drag_function (PsppSheetView *tree_view,
- PsppSheetViewColumnDropFunc func,
- gpointer user_data,
- GDestroyNotify destroy)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- if (tree_view->priv->column_drop_func_data_destroy)
- tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
-
- tree_view->priv->column_drop_func = func;
- tree_view->priv->column_drop_func_data = user_data;
- tree_view->priv->column_drop_func_data_destroy = destroy;
-}
-
-/**
- * pspp_sheet_view_scroll_to_point:
- * @tree_view: a #PsppSheetView
- * @tree_x: X coordinate of new top-left pixel of visible area, or -1
- * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
- *
- * Scrolls the tree view such that the top-left corner of the visible
- * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
- * in tree coordinates. The @tree_view must be realized before
- * this function is called. If it isn't, you probably want to be
- * using pspp_sheet_view_scroll_to_cell().
- *
- * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
- **/
-void
-pspp_sheet_view_scroll_to_point (PsppSheetView *tree_view,
- gint tree_x,
- gint tree_y)
-{
- GtkAdjustment *hadj;
- GtkAdjustment *vadj;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
- g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
-
- hadj = tree_view->priv->hadjustment;
- vadj = tree_view->priv->vadjustment;
-
- if (tree_x != -1)
- gtk_adjustment_set_value (hadj, CLAMP (tree_x, gtk_adjustment_get_lower (hadj), gtk_adjustment_get_upper (hadj) - gtk_adjustment_get_page_size (hadj)));
- if (tree_y != -1)
- gtk_adjustment_set_value (vadj, CLAMP (tree_y, gtk_adjustment_get_lower (vadj), gtk_adjustment_get_upper (vadj) - gtk_adjustment_get_page_size (vadj)));
-}
-
-/**
- * pspp_sheet_view_scroll_to_cell:
- * @tree_view: A #PsppSheetView.
- * @path: (allow-none): The path of the row to move to, or %NULL.
- * @column: (allow-none): The #PsppSheetViewColumn to move horizontally to, or %NULL.
- * @use_align: whether to use alignment arguments, or %FALSE.
- * @row_align: The vertical alignment of the row specified by @path.
- * @col_align: The horizontal alignment of the column specified by @column.
- *
- * Moves the alignments of @tree_view to the position specified by @column and
- * @path. If @column is %NULL, then no horizontal scrolling occurs. Likewise,
- * if @path is %NULL no vertical scrolling occurs. At a minimum, one of @column
- * or @path need to be non-%NULL. @row_align determines where the row is
- * placed, and @col_align determines where @column is placed. Both are expected
- * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
- * right/bottom alignment, 0.5 means center.
- *
- * If @use_align is %FALSE, then the alignment arguments are ignored, and the
- * tree does the minimum amount of work to scroll the cell onto the screen.
- * This means that the cell will be scrolled to the edge closest to its current
- * position. If the cell is currently visible on the screen, nothing is done.
- *
- * This function only works if the model is set, and @path is a valid row on the
- * model. If the model changes before the @tree_view is realized, the centered
- * path will be modified to reflect this change.
- **/
-void
-pspp_sheet_view_scroll_to_cell (PsppSheetView *tree_view,
- GtkTreePath *path,
- PsppSheetViewColumn *column,
- gboolean use_align,
- gfloat row_align,
- gfloat col_align)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
- g_return_if_fail (tree_view->priv->model != NULL);
- g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
- g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
- g_return_if_fail (path != NULL || column != NULL);
-
-#if 0
- g_print ("pspp_sheet_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
- gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
-#endif
- row_align = CLAMP (row_align, 0.0, 1.0);
- col_align = CLAMP (col_align, 0.0, 1.0);
-
-
- /* Note: Despite the benefits that come from having one code path for the
- * scrolling code, we short-circuit validate_visible_area's immplementation as
- * it is much slower than just going to the point.
- */
- if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
- !gtk_widget_get_realized (GTK_WIDGET (tree_view))
- /* XXX || GTK_WIDGET_ALLOC_NEEDED (tree_view) */)
- {
- if (tree_view->priv->scroll_to_path)
- gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
-
- tree_view->priv->scroll_to_path = NULL;
- tree_view->priv->scroll_to_column = NULL;
-
- if (path)
- tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
- if (column)
- tree_view->priv->scroll_to_column = column;
- tree_view->priv->scroll_to_use_align = use_align;
- tree_view->priv->scroll_to_row_align = row_align;
- tree_view->priv->scroll_to_col_align = col_align;
-
- install_presize_handler (tree_view);
- }
- else
- {
- GdkRectangle cell_rect;
- GdkRectangle vis_rect;
- gint dest_x, dest_y;
-
- pspp_sheet_view_get_background_area (tree_view, path, column, &cell_rect);
- pspp_sheet_view_get_visible_rect (tree_view, &vis_rect);
-
- cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
-
- dest_x = vis_rect.x;
- dest_y = vis_rect.y;
-
- if (column)
- {
- if (use_align)
- {
- dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
- }
- else
- {
- if (cell_rect.x < vis_rect.x)
- dest_x = cell_rect.x;
- if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
- dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
- }
- }
-
- if (path)
- {
- if (use_align)
- {
- dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
- dest_y = MAX (dest_y, 0);
- }
- else
- {
- if (cell_rect.y < vis_rect.y)
- dest_y = cell_rect.y;
- if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
- dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
- }
- }
-
- pspp_sheet_view_scroll_to_point (tree_view, dest_x, dest_y);
- }
-}
-
-/**
- * pspp_sheet_view_row_activated:
- * @tree_view: A #PsppSheetView
- * @path: The #GtkTreePath to be activated.
- * @column: The #PsppSheetViewColumn to be activated.
- *
- * Activates the cell determined by @path and @column.
- **/
-void
-pspp_sheet_view_row_activated (PsppSheetView *tree_view,
- GtkTreePath *path,
- PsppSheetViewColumn *column)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
-}
-
-
-/**
- * pspp_sheet_view_get_reorderable:
- * @tree_view: a #PsppSheetView
- *
- * Retrieves whether the user can reorder the tree via drag-and-drop. See
- * pspp_sheet_view_set_reorderable().
- *
- * Return value: %TRUE if the tree can be reordered.
- **/
-gboolean
-pspp_sheet_view_get_reorderable (PsppSheetView *tree_view)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
-
- return tree_view->priv->reorderable;
-}
-
-/**
- * pspp_sheet_view_set_reorderable:
- * @tree_view: A #PsppSheetView.
- * @reorderable: %TRUE, if the tree can be reordered.
- *
- * This function is a convenience function to allow you to reorder
- * models that support the #GtkDragSourceIface and the
- * #GtkDragDestIface. Both #GtkTreeStore and #GtkListStore support
- * these. If @reorderable is %TRUE, then the user can reorder the
- * model by dragging and dropping rows. The developer can listen to
- * these changes by connecting to the model's row_inserted and
- * row_deleted signals. The reordering is implemented by setting up
- * the tree view as a drag source and destination. Therefore, drag and
- * drop can not be used in a reorderable view for any other purpose.
- *
- * This function does not give you any degree of control over the order -- any
- * reordering is allowed. If more control is needed, you should probably
- * handle drag and drop manually.
- **/
-void
-pspp_sheet_view_set_reorderable (PsppSheetView *tree_view,
- gboolean reorderable)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- reorderable = reorderable != FALSE;
-
- if (tree_view->priv->reorderable == reorderable)
- return;
-
- if (reorderable)
- {
- const GtkTargetEntry row_targets[] = {
- { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
- };
-
- pspp_sheet_view_enable_model_drag_source (tree_view,
- GDK_BUTTON1_MASK,
- row_targets,
- G_N_ELEMENTS (row_targets),
- GDK_ACTION_MOVE);
- pspp_sheet_view_enable_model_drag_dest (tree_view,
- row_targets,
- G_N_ELEMENTS (row_targets),
- GDK_ACTION_MOVE);
- }
- else
- {
- pspp_sheet_view_unset_rows_drag_source (tree_view);
- pspp_sheet_view_unset_rows_drag_dest (tree_view);
- }
-
- tree_view->priv->reorderable = reorderable;
-
- g_object_notify (G_OBJECT (tree_view), "reorderable");
-}
-
-/* If CLEAR_AND_SELECT is true, then the row will be selected and, unless Shift
- is pressed, other rows will be unselected.
-
- If CLAMP_NODE is true, then the sheetview will scroll to make the row
- visible. */
-static void
-pspp_sheet_view_real_set_cursor (PsppSheetView *tree_view,
- GtkTreePath *path,
- gboolean clear_and_select,
- gboolean clamp_node,
- PsppSheetSelectMode mode)
-{
- int node = -1;
-
- if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
- {
- GtkTreePath *cursor_path;
- cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
- pspp_sheet_view_queue_draw_path (tree_view, cursor_path, NULL);
- gtk_tree_path_free (cursor_path);
- }
-
- gtk_tree_row_reference_free (tree_view->priv->cursor);
- tree_view->priv->cursor = NULL;
-
- _pspp_sheet_view_find_node (tree_view, path, &node);
- tree_view->priv->cursor =
- gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
- tree_view->priv->model,
- path);
-
- if (tree_view->priv->row_count > 0)
- {
- int new_node = -1;
-
- if (clear_and_select && !(mode & PSPP_SHEET_SELECT_MODE_TOGGLE))
- _pspp_sheet_selection_internal_select_node (tree_view->priv->selection,
- node, path, mode,
- FALSE);
-
- /* We have to re-find tree and node here again, somebody might have
- * cleared the node or the whole tree in the PsppSheetSelection::changed
- * callback. If the nodes differ we bail out here.
- */
- _pspp_sheet_view_find_node (tree_view, path, &new_node);
-
- if (node != new_node)
- return;
-
- if (clamp_node)
- {
- pspp_sheet_view_clamp_node_visible (tree_view, node);
- _pspp_sheet_view_queue_draw_node (tree_view, node, NULL);
- }
- }
-
- g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
-}
-
-/**
- * pspp_sheet_view_get_cursor:
- * @tree_view: A #PsppSheetView
- * @path: (allow-none): A pointer to be filled with the current cursor path, or %NULL
- * @focus_column: (allow-none): A pointer to be filled with the current focus column, or %NULL
- *
- * Fills in @path and @focus_column with the current path and focus column. If
- * the cursor isn't currently set, then *@path will be %NULL. If no column
- * currently has focus, then *@focus_column will be %NULL.
- *
- * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
- * you are done with it.
- **/
-void
-pspp_sheet_view_get_cursor (PsppSheetView *tree_view,
- GtkTreePath **path,
- PsppSheetViewColumn **focus_column)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- if (path)
- {
- if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
- *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
- else
- *path = NULL;
- }
-
- if (focus_column)
- {
- *focus_column = tree_view->priv->focus_column;
- }
-}
-
-/**
- * pspp_sheet_view_set_cursor:
- * @tree_view: A #PsppSheetView
- * @path: A #GtkTreePath
- * @focus_column: (allow-none): A #PsppSheetViewColumn, or %NULL
- * @start_editing: %TRUE if the specified cell should start being edited.
- *
- * Sets the current keyboard focus to be at @path, and selects it. This is
- * useful when you want to focus the user's attention on a particular row. If
- * @focus_column is not %NULL, then focus is given to the column specified by
- * it. Additionally, if @focus_column is specified, and @start_editing is
- * %TRUE, then editing should be started in the specified cell.
- * This function is often followed by @gtk_widget_grab_focus (@tree_view)
- * in order to give keyboard focus to the widget. Please note that editing
- * can only happen when the widget is realized.
- *
- * If @path is invalid for @model, the current cursor (if any) will be unset
- * and the function will return without failing.
- **/
-void
-pspp_sheet_view_set_cursor (PsppSheetView *tree_view,
- GtkTreePath *path,
- PsppSheetViewColumn *focus_column,
- gboolean start_editing)
-{
- pspp_sheet_view_set_cursor_on_cell (tree_view, path, focus_column,
- NULL, start_editing);
-}
-
-/**
- * pspp_sheet_view_set_cursor_on_cell:
- * @tree_view: A #PsppSheetView
- * @path: A #GtkTreePath
- * @focus_column: (allow-none): A #PsppSheetViewColumn, or %NULL
- * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
- * @start_editing: %TRUE if the specified cell should start being edited.
- *
- * Sets the current keyboard focus to be at @path, and selects it. This is
- * useful when you want to focus the user's attention on a particular row. If
- * @focus_column is not %NULL, then focus is given to the column specified by
- * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
- * contains 2 or more editable or activatable cells, then focus is given to
- * the cell specified by @focus_cell. Additionally, if @focus_column is
- * specified, and @start_editing is %TRUE, then editing should be started in
- * the specified cell. This function is often followed by
- * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
- * widget. Please note that editing can only happen when the widget is
- * realized.
- *
- * If @path is invalid for @model, the current cursor (if any) will be unset
- * and the function will return without failing.
- *
- * Since: 2.2
- **/
-void
-pspp_sheet_view_set_cursor_on_cell (PsppSheetView *tree_view,
- GtkTreePath *path,
- PsppSheetViewColumn *focus_column,
- GtkCellRenderer *focus_cell,
- gboolean start_editing)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
- g_return_if_fail (path != NULL);
- g_return_if_fail (focus_column == NULL || PSPP_IS_SHEET_VIEW_COLUMN (focus_column));
-
- if (!tree_view->priv->model)
- return;
-
- if (focus_cell)
- {
- g_return_if_fail (focus_column);
- g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
- }
-
- /* cancel the current editing, if it exists */
- if (tree_view->priv->edited_column &&
- tree_view->priv->edited_column->editable_widget)
- pspp_sheet_view_stop_editing (tree_view, TRUE);
-
- pspp_sheet_view_real_set_cursor (tree_view, path, TRUE, TRUE, 0);
-
- if (focus_column && focus_column->visible)
- {
- GList *list;
- gboolean column_in_tree = FALSE;
-
- for (list = tree_view->priv->columns; list; list = list->next)
- if (list->data == focus_column)
- {
- column_in_tree = TRUE;
- break;
- }
- g_return_if_fail (column_in_tree);
- tree_view->priv->focus_column = focus_column;
- if (focus_cell)
- pspp_sheet_view_column_focus_cell (focus_column, focus_cell);
- if (start_editing)
- pspp_sheet_view_start_editing (tree_view, path);
-
- pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection);
- pspp_sheet_selection_select_column (tree_view->priv->selection, focus_column);
-
- }
-}
-
-/**
- * pspp_sheet_view_get_bin_window:
- * @tree_view: A #PsppSheetView
- *
- * Returns the window that @tree_view renders to. This is used primarily to
- * compare to <literal>event->window</literal> to confirm that the event on
- * @tree_view is on the right window.
- *
- * Return value: A #GdkWindow, or %NULL when @tree_view hasn't been realized yet
- **/
-GdkWindow *
-pspp_sheet_view_get_bin_window (PsppSheetView *tree_view)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
- return tree_view->priv->bin_window;
-}
-
-/**
- * pspp_sheet_view_get_path_at_pos:
- * @tree_view: A #PsppSheetView.
- * @x: The x position to be identified (relative to bin_window).
- * @y: The y position to be identified (relative to bin_window).
- * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
- * @column: (out) (allow-none): A pointer to a #PsppSheetViewColumn pointer to be filled in, or %NULL
- * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
- * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
- *
- * Finds the path at the point (@x, @y), relative to bin_window coordinates
- * (please see pspp_sheet_view_get_bin_window()).
- * That is, @x and @y are relative to an events coordinates. @x and @y must
- * come from an event on the @tree_view only where <literal>event->window ==
- * pspp_sheet_view_get_bin_window (<!-- -->)</literal>. It is primarily for
- * things like popup menus. If @path is non-%NULL, then it will be filled
- * with the #GtkTreePath at that point. This path should be freed with
- * gtk_tree_path_free(). If @column is non-%NULL, then it will be filled
- * with the column at that point. @cell_x and @cell_y return the coordinates
- * relative to the cell background (i.e. the @background_area passed to
- * gtk_cell_renderer_render()). This function is only meaningful if
- * @tree_view is realized. Therefore this function will always return %FALSE
- * if @tree_view is not realized or does not have a model.
- *
- * For converting widget coordinates (eg. the ones you get from
- * GtkWidget::query-tooltip), please see
- * pspp_sheet_view_convert_widget_to_bin_window_coords().
- *
- * Return value: %TRUE if a row exists at that coordinate.
- **/
-gboolean
-pspp_sheet_view_get_path_at_pos (PsppSheetView *tree_view,
- gint x,
- gint y,
- GtkTreePath **path,
- PsppSheetViewColumn **column,
- gint *cell_x,
- gint *cell_y)
-{
- int node;
- gint y_offset;
-
- g_return_val_if_fail (tree_view != NULL, FALSE);
-
- if (path)
- *path = NULL;
- if (column)
- *column = NULL;
-
- if (tree_view->priv->bin_window == NULL)
- return FALSE;
-
- if (tree_view->priv->row_count == 0)
- return FALSE;
-
- if (x > gtk_adjustment_get_upper (tree_view->priv->hadjustment))
- return FALSE;
-
- if (x < 0 || y < 0)
- return FALSE;
-
- if (column || cell_x)
- {
- PsppSheetViewColumn *tmp_column;
- PsppSheetViewColumn *last_column = NULL;
- GList *list;
- gint remaining_x = x;
- gboolean found = FALSE;
- gboolean rtl;
-
- rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
- for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
- list;
- list = (rtl ? list->prev : list->next))
- {
- tmp_column = list->data;
-
- if (tmp_column->visible == FALSE)
- continue;
-
- last_column = tmp_column;
- if (remaining_x <= tmp_column->width)
- {
- found = TRUE;
-
- if (column)
- *column = tmp_column;
-
- if (cell_x)
- *cell_x = remaining_x;
-
- break;
- }
- remaining_x -= tmp_column->width;
- }
-
- /* If found is FALSE and there is a last_column, then it the remainder
- * space is in that area
- */
- if (!found)
- {
- if (last_column)
- {
- if (column)
- *column = last_column;
-
- if (cell_x)
- *cell_x = last_column->width + remaining_x;
- }
- else
- {
- return FALSE;
- }
- }
- }
-
- y_offset = pspp_sheet_view_find_offset (tree_view,
- TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
- &node);
-
- if (node < 0)
- return FALSE;
-
- if (cell_y)
- *cell_y = y_offset;
-
- if (path)
- *path = _pspp_sheet_view_find_path (tree_view, node);
-
- return TRUE;
-}
-
-/* Computes 'cell_area' from 'background_area', which must be the background
- area for a cell. Set 'subtract_focus_rect' to TRUE to compute the cell area
- as passed to a GtkCellRenderer's "render" function, or to FALSE to compute
- the cell area as passed to _pspp_sheet_view_column_cell_render().
-
- 'column' is required to properly adjust 'cell_area->x' and
- 'cell_area->width'. It may be set to NULL if these values are not of
- interest. In this case 'cell_area->x' and 'cell_area->width' will be
- returned as 0. */
-static void
-pspp_sheet_view_adjust_cell_area (PsppSheetView *tree_view,
- PsppSheetViewColumn *column,
- const GdkRectangle *background_area,
- gboolean subtract_focus_rect,
- GdkRectangle *cell_area)
-{
- gint vertical_separator;
- gint horizontal_separator;
-
- *cell_area = *background_area;
-
- gtk_widget_style_get (GTK_WIDGET (tree_view),
- "vertical-separator", &vertical_separator,
- "horizontal-separator", &horizontal_separator,
- NULL);
- cell_area->x += horizontal_separator / 2;
- cell_area->y += vertical_separator / 2;
- cell_area->width -= horizontal_separator;
- cell_area->height -= vertical_separator;
-
- if (subtract_focus_rect)
- {
- int focus_line_width;
-
- gtk_widget_style_get (GTK_WIDGET (tree_view),
- "focus-line-width", &focus_line_width,
- NULL);
- cell_area->x += focus_line_width;
- cell_area->y += focus_line_width;
- cell_area->width -= 2 * focus_line_width;
- cell_area->height -= 2 * focus_line_width;
- }
-
- if (tree_view->priv->grid_lines != PSPP_SHEET_VIEW_GRID_LINES_NONE)
- {
- gint grid_line_width;
- gtk_widget_style_get (GTK_WIDGET (tree_view),
- "grid-line-width", &grid_line_width,
- NULL);
-
- if ((tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_VERTICAL
- || tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_BOTH)
- && column != NULL)
- {
- PsppSheetViewColumn *first_column, *last_column;
- GList *list;
-
- /* Find the last visible column. */
- last_column = NULL;
- for (list = g_list_last (tree_view->priv->columns);
- list;
- list = list->prev)
- {
- PsppSheetViewColumn *c = list->data;
- if (c->visible)
- {
- last_column = c;
- break;
- }
- }
-
- /* Find the first visible column. */
- first_column = NULL;
- for (list = g_list_first (tree_view->priv->columns);
- list;
- list = list->next)
- {
- PsppSheetViewColumn *c = list->data;
- if (c->visible)
- {
- first_column = c;
- break;
- }
- }
-
- if (column == first_column)
- {
- cell_area->width -= grid_line_width / 2;
- }
- else if (column == last_column)
- {
- cell_area->x += grid_line_width / 2;
- cell_area->width -= grid_line_width / 2;
- }
- else
- {
- cell_area->x += grid_line_width / 2;
- cell_area->width -= grid_line_width;
- }
- }
-
- if (tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_HORIZONTAL
- || tree_view->priv->grid_lines == PSPP_SHEET_VIEW_GRID_LINES_BOTH)
- {
- cell_area->y += grid_line_width / 2;
- cell_area->height -= grid_line_width;
- }
- }
-
- if (column == NULL)
- {
- cell_area->x = 0;
- cell_area->width = 0;
- }
-}
-
-/**
- * pspp_sheet_view_get_cell_area:
- * @tree_view: a #PsppSheetView
- * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
- * @column: (allow-none): a #PsppSheetViewColumn for the column, or %NULL to get only vertical coordinates
- * @rect: rectangle to fill with cell rect
- *
- * Fills the bounding rectangle in bin_window coordinates for the cell at the
- * row specified by @path and the column specified by @column. If @path is
- * %NULL, or points to a path not currently displayed, the @y and @height fields
- * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
- * fields will be filled with 0. The sum of all cell rects does not cover the
- * entire tree; there are extra pixels in between rows, for example. The
- * returned rectangle is equivalent to the @cell_area passed to
- * gtk_cell_renderer_render(). This function is only valid if @tree_view is
- * realized.
- **/
-void
-pspp_sheet_view_get_cell_area (PsppSheetView *tree_view,
- GtkTreePath *path,
- PsppSheetViewColumn *column,
- GdkRectangle *rect)
-{
- GdkRectangle background_area;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
- g_return_if_fail (column == NULL || PSPP_IS_SHEET_VIEW_COLUMN (column));
- g_return_if_fail (rect != NULL);
- g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
- g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
-
- pspp_sheet_view_get_background_area (tree_view, path, column,
- &background_area);
- pspp_sheet_view_adjust_cell_area (tree_view, column, &background_area,
- FALSE, rect);
-}
-
-/**
- * pspp_sheet_view_get_background_area:
- * @tree_view: a #PsppSheetView
- * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
- * @column: (allow-none): a #PsppSheetViewColumn for the column, or %NULL to get only vertical coordiantes
- * @rect: rectangle to fill with cell background rect
- *
- * Fills the bounding rectangle in bin_window coordinates for the cell at the
- * row specified by @path and the column specified by @column. If @path is
- * %NULL, or points to a node not found in the tree, the @y and @height fields of
- * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
- * fields will be filled with 0. The returned rectangle is equivalent to the
- * @background_area passed to gtk_cell_renderer_render(). These background
- * areas tile to cover the entire bin window. Contrast with the @cell_area,
- * returned by pspp_sheet_view_get_cell_area(), which returns only the cell
- * itself, excluding surrounding borders.
- *
- **/
-void
-pspp_sheet_view_get_background_area (PsppSheetView *tree_view,
- GtkTreePath *path,
- PsppSheetViewColumn *column,
- GdkRectangle *rect)
-{
- int node = -1;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
- g_return_if_fail (column == NULL || PSPP_IS_SHEET_VIEW_COLUMN (column));
- g_return_if_fail (rect != NULL);
-
- rect->x = 0;
- rect->y = 0;
- rect->width = 0;
- rect->height = 0;
-
- if (path)
- {
- /* Get vertical coords */
-
- _pspp_sheet_view_find_node (tree_view, path, &node);
- if (node < 0)
- return;
-
- rect->y = BACKGROUND_FIRST_PIXEL (tree_view, node);
-
- rect->height = ROW_HEIGHT (tree_view);
- }
-
- if (column)
- {
- gint x2 = 0;
-
- pspp_sheet_view_get_background_xrange (tree_view, column, &rect->x, &x2);
- rect->width = x2 - rect->x;
- }
-}
-
-/**
- * pspp_sheet_view_get_visible_rect:
- * @tree_view: a #PsppSheetView
- * @visible_rect: rectangle to fill
- *
- * Fills @visible_rect with the currently-visible region of the
- * buffer, in tree coordinates. Convert to bin_window coordinates with
- * pspp_sheet_view_convert_tree_to_bin_window_coords().
- * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
- * scrollable area of the tree.
- **/
-void
-pspp_sheet_view_get_visible_rect (PsppSheetView *tree_view,
- GdkRectangle *visible_rect)
-{
- GtkWidget *widget;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- widget = GTK_WIDGET (tree_view);
-
- if (visible_rect)
- {
- GtkAllocation allocation;
- gtk_widget_get_allocation (widget, &allocation);
- visible_rect->x = gtk_adjustment_get_value (tree_view->priv->hadjustment);
- visible_rect->y = gtk_adjustment_get_value (tree_view->priv->vadjustment);
- visible_rect->width = allocation.width;
- visible_rect->height = allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
- }
-}
-
-/**
- * pspp_sheet_view_widget_to_tree_coords:
- * @tree_view: a #PsppSheetView
- * @wx: X coordinate relative to bin_window
- * @wy: Y coordinate relative to bin_window
- * @tx: return location for tree X coordinate
- * @ty: return location for tree Y coordinate
- *
- * Converts bin_window coordinates to coordinates for the
- * tree (the full scrollable area of the tree).
- *
- * Deprecated: 2.12: Due to historial reasons the name of this function is
- * incorrect. For converting coordinates relative to the widget to
- * bin_window coordinates, please see
- * pspp_sheet_view_convert_widget_to_bin_window_coords().
- *
- **/
-void
-pspp_sheet_view_widget_to_tree_coords (PsppSheetView *tree_view,
- gint wx,
- gint wy,
- gint *tx,
- gint *ty)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- if (tx)
- *tx = wx + gtk_adjustment_get_value (tree_view->priv->hadjustment);
- if (ty)
- *ty = wy + tree_view->priv->dy;
-}
-
-/**
- * pspp_sheet_view_tree_to_widget_coords:
- * @tree_view: a #PsppSheetView
- * @tx: tree X coordinate
- * @ty: tree Y coordinate
- * @wx: return location for X coordinate relative to bin_window
- * @wy: return location for Y coordinate relative to bin_window
- *
- * Converts tree coordinates (coordinates in full scrollable area of the tree)
- * to bin_window coordinates.
- *
- * Deprecated: 2.12: Due to historial reasons the name of this function is
- * incorrect. For converting bin_window coordinates to coordinates relative
- * to bin_window, please see
- * pspp_sheet_view_convert_bin_window_to_widget_coords().
- *
- **/
-void
-pspp_sheet_view_tree_to_widget_coords (PsppSheetView *tree_view,
- gint tx,
- gint ty,
- gint *wx,
- gint *wy)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- if (wx)
- *wx = tx - gtk_adjustment_get_value (tree_view->priv->hadjustment);
- if (wy)
- *wy = ty - tree_view->priv->dy;
-}
-
-
-/**
- * pspp_sheet_view_convert_widget_to_tree_coords:
- * @tree_view: a #PsppSheetView
- * @wx: X coordinate relative to the widget
- * @wy: Y coordinate relative to the widget
- * @tx: return location for tree X coordinate
- * @ty: return location for tree Y coordinate
- *
- * Converts widget coordinates to coordinates for the
- * tree (the full scrollable area of the tree).
- *
- * Since: 2.12
- **/
-void
-pspp_sheet_view_convert_widget_to_tree_coords (PsppSheetView *tree_view,
- gint wx,
- gint wy,
- gint *tx,
- gint *ty)
-{
- gint x, y;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view,
- wx, wy,
- &x, &y);
- pspp_sheet_view_convert_bin_window_to_tree_coords (tree_view,
- x, y,
- tx, ty);
-}
-
-/**
- * pspp_sheet_view_convert_tree_to_widget_coords:
- * @tree_view: a #PsppSheetView
- * @tx: X coordinate relative to the tree
- * @ty: Y coordinate relative to the tree
- * @wx: return location for widget X coordinate
- * @wy: return location for widget Y coordinate
- *
- * Converts tree coordinates (coordinates in full scrollable area of the tree)
- * to widget coordinates.
- *
- * Since: 2.12
- **/
-void
-pspp_sheet_view_convert_tree_to_widget_coords (PsppSheetView *tree_view,
- gint tx,
- gint ty,
- gint *wx,
- gint *wy)
-{
- gint x, y;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- pspp_sheet_view_convert_tree_to_bin_window_coords (tree_view,
- tx, ty,
- &x, &y);
- pspp_sheet_view_convert_bin_window_to_widget_coords (tree_view,
- x, y,
- wx, wy);
-}
-
-/**
- * pspp_sheet_view_convert_widget_to_bin_window_coords:
- * @tree_view: a #PsppSheetView
- * @wx: X coordinate relative to the widget
- * @wy: Y coordinate relative to the widget
- * @bx: return location for bin_window X coordinate
- * @by: return location for bin_window Y coordinate
- *
- * Converts widget coordinates to coordinates for the bin_window
- * (see pspp_sheet_view_get_bin_window()).
- *
- * Since: 2.12
- **/
-void
-pspp_sheet_view_convert_widget_to_bin_window_coords (PsppSheetView *tree_view,
- gint wx,
- gint wy,
- gint *bx,
- gint *by)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- if (bx)
- *bx = wx + gtk_adjustment_get_value (tree_view->priv->hadjustment);
- if (by)
- *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
-}
-
-/**
- * pspp_sheet_view_convert_bin_window_to_widget_coords:
- * @tree_view: a #PsppSheetView
- * @bx: bin_window X coordinate
- * @by: bin_window Y coordinate
- * @wx: return location for widget X coordinate
- * @wy: return location for widget Y coordinate
- *
- * Converts bin_window coordinates (see pspp_sheet_view_get_bin_window())
- * to widget relative coordinates.
- *
- * Since: 2.12
- **/
-void
-pspp_sheet_view_convert_bin_window_to_widget_coords (PsppSheetView *tree_view,
- gint bx,
- gint by,
- gint *wx,
- gint *wy)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- if (wx)
- *wx = bx - gtk_adjustment_get_value (tree_view->priv->hadjustment);
- if (wy)
- *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
-}
-
-/**
- * pspp_sheet_view_convert_tree_to_bin_window_coords:
- * @tree_view: a #PsppSheetView
- * @tx: tree X coordinate
- * @ty: tree Y coordinate
- * @bx: return location for X coordinate relative to bin_window
- * @by: return location for Y coordinate relative to bin_window
- *
- * Converts tree coordinates (coordinates in full scrollable area of the tree)
- * to bin_window coordinates.
- *
- * Since: 2.12
- **/
-void
-pspp_sheet_view_convert_tree_to_bin_window_coords (PsppSheetView *tree_view,
- gint tx,
- gint ty,
- gint *bx,
- gint *by)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- if (bx)
- *bx = tx;
- if (by)
- *by = ty - tree_view->priv->dy;
-}
-
-/**
- * pspp_sheet_view_convert_bin_window_to_tree_coords:
- * @tree_view: a #PsppSheetView
- * @bx: X coordinate relative to bin_window
- * @by: Y coordinate relative to bin_window
- * @tx: return location for tree X coordinate
- * @ty: return location for tree Y coordinate
- *
- * Converts bin_window coordinates to coordinates for the
- * tree (the full scrollable area of the tree).
- *
- * Since: 2.12
- **/
-void
-pspp_sheet_view_convert_bin_window_to_tree_coords (PsppSheetView *tree_view,
- gint bx,
- gint by,
- gint *tx,
- gint *ty)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- if (tx)
- *tx = bx;
- if (ty)
- *ty = by + tree_view->priv->dy;
-}
-
-
-
-/**
- * pspp_sheet_view_get_visible_range:
- * @tree_view: A #PsppSheetView
- * @start_path: (allow-none): Return location for start of region, or %NULL.
- * @end_path: (allow-none): Return location for end of region, or %NULL.
- *
- * Sets @start_path and @end_path to be the first and last visible path.
- * Note that there may be invisible paths in between.
- *
- * The paths should be freed with gtk_tree_path_free() after use.
- *
- * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
- *
- * Since: 2.8
- **/
-gboolean
-pspp_sheet_view_get_visible_range (PsppSheetView *tree_view,
- GtkTreePath **start_path,
- GtkTreePath **end_path)
-{
- int node;
- gboolean retval;
-
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
-
- if (!tree_view->priv->row_count)
- return FALSE;
-
- retval = TRUE;
-
- if (start_path)
- {
- pspp_sheet_view_find_offset (tree_view,
- TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
- &node);
- if (node >= 0)
- *start_path = _pspp_sheet_view_find_path (tree_view, node);
- else
- retval = FALSE;
- }
-
- if (end_path)
- {
- gint y;
-
- if (tree_view->priv->height < gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
- y = tree_view->priv->height - 1;
- else
- y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, gtk_adjustment_get_page_size (tree_view->priv->vadjustment)) - 1;
-
- pspp_sheet_view_find_offset (tree_view, y, &node);
- if (node >= 0)
- *end_path = _pspp_sheet_view_find_path (tree_view, node);
- else
- retval = FALSE;
- }
-
- return retval;
-}
-
-static void
-unset_reorderable (PsppSheetView *tree_view)
-{
- if (tree_view->priv->reorderable)
- {
- tree_view->priv->reorderable = FALSE;
- g_object_notify (G_OBJECT (tree_view), "reorderable");
- }
-}
-
-/**
- * pspp_sheet_view_enable_model_drag_source:
- * @tree_view: a #PsppSheetView
- * @start_button_mask: Mask of allowed buttons to start drag
- * @targets: the table of targets that the drag will support
- * @n_targets: the number of items in @targets
- * @actions: the bitmask of possible actions for a drag from this
- * widget
- *
- * Turns @tree_view into a drag source for automatic DND. Calling this
- * method sets #PsppSheetView:reorderable to %FALSE.
- **/
-void
-pspp_sheet_view_enable_model_drag_source (PsppSheetView *tree_view,
- GdkModifierType start_button_mask,
- const GtkTargetEntry *targets,
- gint n_targets,
- GdkDragAction actions)
-{
- TreeViewDragInfo *di;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- gtk_drag_source_set (GTK_WIDGET (tree_view),
- 0,
- targets,
- n_targets,
- actions);
-
- di = ensure_info (tree_view);
-
- di->start_button_mask = start_button_mask;
- di->source_actions = actions;
- di->source_set = TRUE;
-
- unset_reorderable (tree_view);
-}
-
-/**
- * pspp_sheet_view_enable_model_drag_dest:
- * @tree_view: a #PsppSheetView
- * @targets: the table of targets that the drag will support
- * @n_targets: the number of items in @targets
- * @actions: the bitmask of possible actions for a drag from this
- * widget
- *
- * Turns @tree_view into a drop destination for automatic DND. Calling
- * this method sets #PsppSheetView:reorderable to %FALSE.
- **/
-void
-pspp_sheet_view_enable_model_drag_dest (PsppSheetView *tree_view,
- const GtkTargetEntry *targets,
- gint n_targets,
- GdkDragAction actions)
-{
- TreeViewDragInfo *di;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- gtk_drag_dest_set (GTK_WIDGET (tree_view),
- 0,
- targets,
- n_targets,
- actions);
-
- di = ensure_info (tree_view);
- di->dest_set = TRUE;
-
- unset_reorderable (tree_view);
-}
-
-/**
- * pspp_sheet_view_unset_rows_drag_source:
- * @tree_view: a #PsppSheetView
- *
- * Undoes the effect of
- * pspp_sheet_view_enable_model_drag_source(). Calling this method sets
- * #PsppSheetView:reorderable to %FALSE.
- **/
-void
-pspp_sheet_view_unset_rows_drag_source (PsppSheetView *tree_view)
-{
- TreeViewDragInfo *di;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- di = get_info (tree_view);
-
- if (di)
- {
- if (di->source_set)
- {
- gtk_drag_source_unset (GTK_WIDGET (tree_view));
- di->source_set = FALSE;
- }
-
- if (!di->dest_set && !di->source_set)
- remove_info (tree_view);
- }
-
- unset_reorderable (tree_view);
-}
-
-/**
- * pspp_sheet_view_unset_rows_drag_dest:
- * @tree_view: a #PsppSheetView
- *
- * Undoes the effect of
- * pspp_sheet_view_enable_model_drag_dest(). Calling this method sets
- * #PsppSheetView:reorderable to %FALSE.
- **/
-void
-pspp_sheet_view_unset_rows_drag_dest (PsppSheetView *tree_view)
-{
- TreeViewDragInfo *di;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- di = get_info (tree_view);
-
- if (di)
- {
- if (di->dest_set)
- {
- gtk_drag_dest_unset (GTK_WIDGET (tree_view));
- di->dest_set = FALSE;
- }
-
- if (!di->dest_set && !di->source_set)
- remove_info (tree_view);
- }
-
- unset_reorderable (tree_view);
-}
-
-/**
- * pspp_sheet_view_set_drag_dest_row:
- * @tree_view: a #PsppSheetView
- * @path: (allow-none): The path of the row to highlight, or %NULL.
- * @pos: Specifies whether to drop before, after or into the row
- *
- * Sets the row that is highlighted for feedback.
- **/
-void
-pspp_sheet_view_set_drag_dest_row (PsppSheetView *tree_view,
- GtkTreePath *path,
- PsppSheetViewDropPosition pos)
-{
- GtkTreePath *current_dest;
-
- /* Note; this function is exported to allow a custom DND
- * implementation, so it can't touch TreeViewDragInfo
- */
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- current_dest = NULL;
-
- if (tree_view->priv->drag_dest_row)
- {
- current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
- gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
- }
-
- /* special case a drop on an empty model */
- tree_view->priv->empty_view_drop = 0;
-
- if (pos == PSPP_SHEET_VIEW_DROP_BEFORE && path
- && gtk_tree_path_get_depth (path) == 1
- && gtk_tree_path_get_indices (path)[0] == 0)
- {
- gint n_children;
-
- n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
- NULL);
-
- if (!n_children)
- tree_view->priv->empty_view_drop = 1;
- }
-
- tree_view->priv->drag_dest_pos = pos;
-
- if (path)
- {
- tree_view->priv->drag_dest_row =
- gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
- pspp_sheet_view_queue_draw_path (tree_view, path, NULL);
- }
- else
- tree_view->priv->drag_dest_row = NULL;
-
- if (current_dest)
- {
- int node, new_node;
-
- _pspp_sheet_view_find_node (tree_view, current_dest, &node);
- _pspp_sheet_view_queue_draw_node (tree_view, node, NULL);
-
- if (node >= 0)
- {
- new_node = pspp_sheet_view_node_next (tree_view, node);
- if (new_node >= 0)
- _pspp_sheet_view_queue_draw_node (tree_view, new_node, NULL);
-
- new_node = pspp_sheet_view_node_prev (tree_view, node);
- if (new_node >= 0)
- _pspp_sheet_view_queue_draw_node (tree_view, new_node, NULL);
- }
- gtk_tree_path_free (current_dest);
- }
-}
-
-/**
- * pspp_sheet_view_get_drag_dest_row:
- * @tree_view: a #PsppSheetView
- * @path: (allow-none): Return location for the path of the highlighted row, or %NULL.
- * @pos: (allow-none): Return location for the drop position, or %NULL
- *
- * Gets information about the row that is highlighted for feedback.
- **/
-void
-pspp_sheet_view_get_drag_dest_row (PsppSheetView *tree_view,
- GtkTreePath **path,
- PsppSheetViewDropPosition *pos)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- if (path)
- {
- if (tree_view->priv->drag_dest_row)
- *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
- else
- {
- if (tree_view->priv->empty_view_drop)
- *path = gtk_tree_path_new_from_indices (0, -1);
- else
- *path = NULL;
- }
- }
-
- if (pos)
- *pos = tree_view->priv->drag_dest_pos;
-}
-
-/**
- * pspp_sheet_view_get_dest_row_at_pos:
- * @tree_view: a #PsppSheetView
- * @drag_x: the position to determine the destination row for
- * @drag_y: the position to determine the destination row for
- * @path: (allow-none): Return location for the path of the highlighted row, or %NULL.
- * @pos: (allow-none): Return location for the drop position, or %NULL
- *
- * Determines the destination row for a given position. @drag_x and
- * @drag_y are expected to be in widget coordinates. This function is only
- * meaningful if @tree_view is realized. Therefore this function will always
- * return %FALSE if @tree_view is not realized or does not have a model.
- *
- * Return value: whether there is a row at the given position, %TRUE if this
- * is indeed the case.
- **/
-gboolean
-pspp_sheet_view_get_dest_row_at_pos (PsppSheetView *tree_view,
- gint drag_x,
- gint drag_y,
- GtkTreePath **path,
- PsppSheetViewDropPosition *pos)
-{
- gint cell_y;
- gint bin_x, bin_y;
- gdouble offset_into_row;
- gdouble third;
- GdkRectangle cell;
- PsppSheetViewColumn *column = NULL;
- GtkTreePath *tmp_path = NULL;
-
- /* Note; this function is exported to allow a custom DND
- * implementation, so it can't touch TreeViewDragInfo
- */
-
- g_return_val_if_fail (tree_view != NULL, FALSE);
- g_return_val_if_fail (drag_x >= 0, FALSE);
- g_return_val_if_fail (drag_y >= 0, FALSE);
-
- if (path)
- *path = NULL;
-
- if (tree_view->priv->bin_window == NULL)
- return FALSE;
-
- if (tree_view->priv->row_count == 0)
- return FALSE;
-
- /* If in the top third of a row, we drop before that row; if
- * in the bottom third, drop after that row; if in the middle,
- * and the row has children, drop into the row.
- */
- pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
- &bin_x, &bin_y);
-
- if (!pspp_sheet_view_get_path_at_pos (tree_view,
- bin_x,
- bin_y,
- &tmp_path,
- &column,
- NULL,
- &cell_y))
- return FALSE;
-
- pspp_sheet_view_get_background_area (tree_view, tmp_path, column,
- &cell);
-
- offset_into_row = cell_y;
-
- if (path)
- *path = tmp_path;
- else
- gtk_tree_path_free (tmp_path);
-
- tmp_path = NULL;
-
- third = cell.height / 3.0;
-
- if (pos)
- {
- if (offset_into_row < third)
- {
- *pos = PSPP_SHEET_VIEW_DROP_BEFORE;
- }
- else if (offset_into_row < (cell.height / 2.0))
- {
- *pos = PSPP_SHEET_VIEW_DROP_INTO_OR_BEFORE;
- }
- else if (offset_into_row < third * 2.0)
- {
- *pos = PSPP_SHEET_VIEW_DROP_INTO_OR_AFTER;
- }
- else
- {
- *pos = PSPP_SHEET_VIEW_DROP_AFTER;
- }
- }
-
- return TRUE;
-}
-
-
-
-/**
- * pspp_sheet_view_set_destroy_count_func:
- * @tree_view: A #PsppSheetView
- * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
- * @data: (allow-none): User data to be passed to @func, or %NULL
- * @destroy: (allow-none): Destroy notifier for @data, or %NULL
- *
- * This function should almost never be used. It is meant for private use by
- * ATK for determining the number of visible children that are removed when a row is deleted.
- **/
-void
-pspp_sheet_view_set_destroy_count_func (PsppSheetView *tree_view,
- PsppSheetDestroyCountFunc func,
- gpointer data,
- GDestroyNotify destroy)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- if (tree_view->priv->destroy_count_destroy)
- tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
-
- tree_view->priv->destroy_count_func = func;
- tree_view->priv->destroy_count_data = data;
- tree_view->priv->destroy_count_destroy = destroy;
-}
-
-
-/*
- * Interactive search
- */
-
-/**
- * pspp_sheet_view_set_enable_search:
- * @tree_view: A #PsppSheetView
- * @enable_search: %TRUE, if the user can search interactively
- *
- * If @enable_search is set, then the user can type in text to search through
- * the tree interactively (this is sometimes called "typeahead find").
- *
- * Note that even if this is %FALSE, the user can still initiate a search
- * using the "start-interactive-search" key binding.
- */
-void
-pspp_sheet_view_set_enable_search (PsppSheetView *tree_view,
- gboolean enable_search)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- enable_search = !!enable_search;
-
- if (tree_view->priv->enable_search != enable_search)
- {
- tree_view->priv->enable_search = enable_search;
- g_object_notify (G_OBJECT (tree_view), "enable-search");
- }
-}
-
-/**
- * pspp_sheet_view_get_enable_search:
- * @tree_view: A #PsppSheetView
- *
- * Returns whether or not the tree allows to start interactive searching
- * by typing in text.
- *
- * Return value: whether or not to let the user search interactively
- */
-gboolean
-pspp_sheet_view_get_enable_search (PsppSheetView *tree_view)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
-
- return tree_view->priv->enable_search;
-}
-
-
-/**
- * pspp_sheet_view_get_search_column:
- * @tree_view: A #PsppSheetView
- *
- * Gets the column searched on by the interactive search code.
- *
- * Return value: the column the interactive search code searches in.
- */
-gint
-pspp_sheet_view_get_search_column (PsppSheetView *tree_view)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), -1);
-
- return (tree_view->priv->search_column);
-}
-
-/**
- * pspp_sheet_view_set_search_column:
- * @tree_view: A #PsppSheetView
- * @column: the column of the model to search in, or -1 to disable searching
- *
- * Sets @column as the column where the interactive search code should
- * search in for the current model.
- *
- * If the search column is set, users can use the "start-interactive-search"
- * key binding to bring up search popup. The enable-search property controls
- * whether simply typing text will also start an interactive search.
- *
- * Note that @column refers to a column of the current model. The search
- * column is reset to -1 when the model is changed.
- */
-void
-pspp_sheet_view_set_search_column (PsppSheetView *tree_view,
- gint column)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
- g_return_if_fail (column >= -1);
-
- if (tree_view->priv->search_column == column)
- return;
-
- tree_view->priv->search_column = column;
- g_object_notify (G_OBJECT (tree_view), "search-column");
-}
-
-/**
- * pspp_sheet_view_get_search_equal_func:
- * @tree_view: A #PsppSheetView
- *
- * Returns the compare function currently in use.
- *
- * Return value: the currently used compare function for the search code.
- */
-
-PsppSheetViewSearchEqualFunc
-pspp_sheet_view_get_search_equal_func (PsppSheetView *tree_view)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
- return tree_view->priv->search_equal_func;
-}
-
-/**
- * pspp_sheet_view_set_search_equal_func:
- * @tree_view: A #PsppSheetView
- * @search_equal_func: the compare function to use during the search
- * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
- * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
- *
- * Sets the compare function for the interactive search capabilities; note
- * that somewhat like strcmp() returning 0 for equality
- * #PsppSheetViewSearchEqualFunc returns %FALSE on matches.
- **/
-void
-pspp_sheet_view_set_search_equal_func (PsppSheetView *tree_view,
- PsppSheetViewSearchEqualFunc search_equal_func,
- gpointer search_user_data,
- GDestroyNotify search_destroy)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
- g_return_if_fail (search_equal_func != NULL);
-
- if (tree_view->priv->search_destroy)
- tree_view->priv->search_destroy (tree_view->priv->search_user_data);
-
- tree_view->priv->search_equal_func = search_equal_func;
- tree_view->priv->search_user_data = search_user_data;
- tree_view->priv->search_destroy = search_destroy;
- if (tree_view->priv->search_equal_func == NULL)
- tree_view->priv->search_equal_func = pspp_sheet_view_search_equal_func;
-}
-
-/**
- * pspp_sheet_view_get_search_entry:
- * @tree_view: A #PsppSheetView
- *
- * Returns the #GtkEntry which is currently in use as interactive search
- * entry for @tree_view. In case the built-in entry is being used, %NULL
- * will be returned.
- *
- * Return value: the entry currently in use as search entry.
- *
- * Since: 2.10
- */
-GtkEntry *
-pspp_sheet_view_get_search_entry (PsppSheetView *tree_view)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
- if (tree_view->priv->search_custom_entry_set)
- return GTK_ENTRY (tree_view->priv->search_entry);
-
- return NULL;
-}
-
-/**
- * pspp_sheet_view_set_search_entry:
- * @tree_view: A #PsppSheetView
- * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
- *
- * Sets the entry which the interactive search code will use for this
- * @tree_view. This is useful when you want to provide a search entry
- * in our interface at all time at a fixed position. Passing %NULL for
- * @entry will make the interactive search code use the built-in popup
- * entry again.
- *
- * Since: 2.10
- */
-void
-pspp_sheet_view_set_search_entry (PsppSheetView *tree_view,
- GtkEntry *entry)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
- g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
-
- if (tree_view->priv->search_custom_entry_set)
- {
- if (tree_view->priv->search_entry_changed_id)
- {
- g_signal_handler_disconnect (tree_view->priv->search_entry,
- tree_view->priv->search_entry_changed_id);
- tree_view->priv->search_entry_changed_id = 0;
- }
- g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
- G_CALLBACK (pspp_sheet_view_search_key_press_event),
- tree_view);
-
- g_object_unref (tree_view->priv->search_entry);
- }
- else if (tree_view->priv->search_window)
- {
- gtk_widget_destroy (tree_view->priv->search_window);
-
- tree_view->priv->search_window = NULL;
- }
-
- if (entry)
- {
- tree_view->priv->search_entry = g_object_ref (entry);
- tree_view->priv->search_custom_entry_set = TRUE;
-
- if (tree_view->priv->search_entry_changed_id == 0)
- {
- tree_view->priv->search_entry_changed_id =
- g_signal_connect (tree_view->priv->search_entry, "changed",
- G_CALLBACK (pspp_sheet_view_search_init),
- tree_view);
- }
-
- g_signal_connect (tree_view->priv->search_entry, "key-press-event",
- G_CALLBACK (pspp_sheet_view_search_key_press_event),
- tree_view);
-
- pspp_sheet_view_search_init (tree_view->priv->search_entry, tree_view);
- }
- else
- {
- tree_view->priv->search_entry = NULL;
- tree_view->priv->search_custom_entry_set = FALSE;
- }
-}
-
-/**
- * pspp_sheet_view_set_search_position_func:
- * @tree_view: A #PsppSheetView
- * @func: (allow-none): the function to use to position the search dialog, or %NULL
- * to use the default search position function
- * @data: (allow-none): user data to pass to @func, or %NULL
- * @destroy: (allow-none): Destroy notifier for @data, or %NULL
- *
- * Sets the function to use when positioning the search dialog.
- *
- * Since: 2.10
- **/
-void
-pspp_sheet_view_set_search_position_func (PsppSheetView *tree_view,
- PsppSheetViewSearchPositionFunc func,
- gpointer user_data,
- GDestroyNotify destroy)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- if (tree_view->priv->search_position_destroy)
- tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
-
- tree_view->priv->search_position_func = func;
- tree_view->priv->search_position_user_data = user_data;
- tree_view->priv->search_position_destroy = destroy;
- if (tree_view->priv->search_position_func == NULL)
- tree_view->priv->search_position_func = pspp_sheet_view_search_position_func;
-}
-
-/**
- * pspp_sheet_view_get_search_position_func:
- * @tree_view: A #PsppSheetView
- *
- * Returns the positioning function currently in use.
- *
- * Return value: the currently used function for positioning the search dialog.
- *
- * Since: 2.10
- */
-PsppSheetViewSearchPositionFunc
-pspp_sheet_view_get_search_position_func (PsppSheetView *tree_view)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), NULL);
-
- return tree_view->priv->search_position_func;
-}
-
-
-static void
-pspp_sheet_view_search_dialog_hide (GtkWidget *search_dialog,
- PsppSheetView *tree_view)
-{
- if (tree_view->priv->disable_popdown)
- return;
-
- if (tree_view->priv->search_entry_changed_id)
- {
- g_signal_handler_disconnect (tree_view->priv->search_entry,
- tree_view->priv->search_entry_changed_id);
- tree_view->priv->search_entry_changed_id = 0;
- }
- if (tree_view->priv->typeselect_flush_timeout)
- {
- g_source_remove (tree_view->priv->typeselect_flush_timeout);
- tree_view->priv->typeselect_flush_timeout = 0;
- }
-
- if (gtk_widget_get_visible (search_dialog))
- {
- /* send focus-in event */
- send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), FALSE);
- gtk_widget_hide (search_dialog);
- gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
- send_focus_change (GTK_WIDGET (tree_view), TRUE);
- }
-}
-
-static void
-pspp_sheet_view_search_position_func (PsppSheetView *tree_view,
- GtkWidget *search_dialog,
- gpointer user_data)
-{
- gint x, y;
- gint tree_x, tree_y;
- gint tree_width, tree_height;
- GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
- GdkScreen *screen = gdk_window_get_screen (tree_window);
- GtkRequisition requisition;
- gint monitor_num;
- GdkRectangle monitor;
-
- monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
- gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
-
- gtk_widget_realize (search_dialog);
-
- gdk_window_get_origin (tree_window, &tree_x, &tree_y);
- tree_width = gdk_window_get_width (tree_window);
- tree_height = gdk_window_get_height (tree_window);
-
- gtk_widget_size_request (search_dialog, &requisition);
-
- if (tree_x + tree_width > gdk_screen_get_width (screen))
- x = gdk_screen_get_width (screen) - requisition.width;
- else if (tree_x + tree_width - requisition.width < 0)
- x = 0;
- else
- x = tree_x + tree_width - requisition.width;
-
- if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
- y = gdk_screen_get_height (screen) - requisition.height;
- else if (tree_y + tree_height < 0) /* isn't really possible ... */
- y = 0;
- else
- y = tree_y + tree_height;
-
- gtk_window_move (GTK_WINDOW (search_dialog), x, y);
-}
-
-static void
-pspp_sheet_view_search_disable_popdown (GtkEntry *entry,
- GtkMenu *menu,
- gpointer data)
-{
- PsppSheetView *tree_view = (PsppSheetView *)data;
-
- tree_view->priv->disable_popdown = 1;
- g_signal_connect (menu, "hide",
- G_CALLBACK (pspp_sheet_view_search_enable_popdown), data);
-}
-
-
-static void
-pspp_sheet_view_search_activate (GtkEntry *entry,
- PsppSheetView *tree_view)
-{
- GtkTreePath *path;
- int node;
-
- pspp_sheet_view_search_dialog_hide (tree_view->priv->search_window,
- tree_view);
-
- /* If we have a row selected and it's the cursor row, we activate
- * the row XXX */
- if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
- {
- path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-
- _pspp_sheet_view_find_node (tree_view, path, &node);
-
- if (node >= 0 && pspp_sheet_view_node_is_selected (tree_view, node))
- pspp_sheet_view_row_activated (tree_view, path, tree_view->priv->focus_column);
-
- gtk_tree_path_free (path);
- }
-}
-
-static gboolean
-pspp_sheet_view_real_search_enable_popdown (gpointer data)
-{
- PsppSheetView *tree_view = (PsppSheetView *)data;
-
- tree_view->priv->disable_popdown = 0;
-
- return FALSE;
-}
-
-static void
-pspp_sheet_view_search_enable_popdown (GtkWidget *widget,
- gpointer data)
-{
- gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, pspp_sheet_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
-}
-
-static gboolean
-pspp_sheet_view_search_delete_event (GtkWidget *widget,
- GdkEventAny *event,
- PsppSheetView *tree_view)
-{
- g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
-
- pspp_sheet_view_search_dialog_hide (widget, tree_view);
-
- return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_search_button_press_event (GtkWidget *widget,
- GdkEventButton *event,
- PsppSheetView *tree_view)
-{
- g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
-
- pspp_sheet_view_search_dialog_hide (widget, tree_view);
-
- if (event->window == tree_view->priv->bin_window)
- pspp_sheet_view_button_press (GTK_WIDGET (tree_view), event);
-
- return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_search_scroll_event (GtkWidget *widget,
- GdkEventScroll *event,
- PsppSheetView *tree_view)
-{
- gboolean retval = FALSE;
-
- if (event->direction == GDK_SCROLL_UP)
- {
- pspp_sheet_view_search_move (widget, tree_view, TRUE);
- retval = TRUE;
- }
- else if (event->direction == GDK_SCROLL_DOWN)
- {
- pspp_sheet_view_search_move (widget, tree_view, FALSE);
- retval = TRUE;
- }
-
- /* renew the flush timeout */
- if (retval && tree_view->priv->typeselect_flush_timeout
- && !tree_view->priv->search_custom_entry_set)
- {
- g_source_remove (tree_view->priv->typeselect_flush_timeout);
- tree_view->priv->typeselect_flush_timeout =
- gdk_threads_add_timeout (PSPP_SHEET_VIEW_SEARCH_DIALOG_TIMEOUT,
- (GSourceFunc) pspp_sheet_view_search_entry_flush_timeout,
- tree_view);
- }
-
- return retval;
-}
-
-static gboolean
-pspp_sheet_view_search_key_press_event (GtkWidget *widget,
- GdkEventKey *event,
- PsppSheetView *tree_view)
-{
- gboolean retval = FALSE;
-
- g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
-
- /* close window and cancel the search */
- if (!tree_view->priv->search_custom_entry_set
- && (event->keyval == GDK_Escape ||
- event->keyval == GDK_Tab ||
- event->keyval == GDK_KP_Tab ||
- event->keyval == GDK_ISO_Left_Tab))
- {
- pspp_sheet_view_search_dialog_hide (widget, tree_view);
- return TRUE;
- }
-
- /* select previous matching iter */
- if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
- {
- if (!pspp_sheet_view_search_move (widget, tree_view, TRUE))
- gtk_widget_error_bell (widget);
-
- retval = TRUE;
- }
-
- if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
- && (event->keyval == GDK_g || event->keyval == GDK_G))
- {
- if (!pspp_sheet_view_search_move (widget, tree_view, TRUE))
- gtk_widget_error_bell (widget);
-
- retval = TRUE;
- }
-
- /* select next matching iter */
- if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
- {
- if (!pspp_sheet_view_search_move (widget, tree_view, FALSE))
- gtk_widget_error_bell (widget);
-
- retval = TRUE;
- }
-
- if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
- && (event->keyval == GDK_g || event->keyval == GDK_G))
- {
- if (!pspp_sheet_view_search_move (widget, tree_view, FALSE))
- gtk_widget_error_bell (widget);
-
- retval = TRUE;
- }
-
- /* renew the flush timeout */
- if (retval && tree_view->priv->typeselect_flush_timeout
- && !tree_view->priv->search_custom_entry_set)
- {
- g_source_remove (tree_view->priv->typeselect_flush_timeout);
- tree_view->priv->typeselect_flush_timeout =
- gdk_threads_add_timeout (PSPP_SHEET_VIEW_SEARCH_DIALOG_TIMEOUT,
- (GSourceFunc) pspp_sheet_view_search_entry_flush_timeout,
- tree_view);
- }
-
- return retval;
-}
-
-/* this function returns FALSE if there is a search string but
- * nothing was found, and TRUE otherwise.
- */
-static gboolean
-pspp_sheet_view_search_move (GtkWidget *window,
- PsppSheetView *tree_view,
- gboolean up)
-{
- gboolean ret;
- gint len;
- gint count = 0;
- const gchar *text;
- GtkTreeIter iter;
- GtkTreeModel *model;
- PsppSheetSelection *selection;
-
- text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
-
- g_return_val_if_fail (text != NULL, FALSE);
-
- len = strlen (text);
-
- if (up && tree_view->priv->selected_iter == 1)
- return strlen (text) < 1;
-
- len = strlen (text);
-
- if (len < 1)
- return TRUE;
-
- model = pspp_sheet_view_get_model (tree_view);
- selection = pspp_sheet_view_get_selection (tree_view);
-
- /* search */
- pspp_sheet_selection_unselect_all (selection);
- if (!gtk_tree_model_get_iter_first (model, &iter))
- return TRUE;
-
- ret = pspp_sheet_view_search_iter (model, selection, &iter, text,
- &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
-
- if (ret)
- {
- /* found */
- tree_view->priv->selected_iter += up?(-1):(1);
- return TRUE;
- }
- else
- {
- /* return to old iter */
- count = 0;
- gtk_tree_model_get_iter_first (model, &iter);
- pspp_sheet_view_search_iter (model, selection,
- &iter, text,
- &count, tree_view->priv->selected_iter);
- return FALSE;
- }
-}
-
-static gboolean
-pspp_sheet_view_search_equal_func (GtkTreeModel *model,
- gint column,
- const gchar *key,
- GtkTreeIter *iter,
- gpointer search_data)
-{
- gboolean retval = TRUE;
- const gchar *str;
- gchar *normalized_string;
- gchar *normalized_key;
- gchar *case_normalized_string = NULL;
- gchar *case_normalized_key = NULL;
- GValue value = {0,};
- GValue transformed = {0,};
-
- gtk_tree_model_get_value (model, iter, column, &value);
-
- g_value_init (&transformed, G_TYPE_STRING);
-
- if (!g_value_transform (&value, &transformed))
- {
- g_value_unset (&value);
- return TRUE;
- }
-
- g_value_unset (&value);
-
- str = g_value_get_string (&transformed);
- if (!str)
- {
- g_value_unset (&transformed);
- return TRUE;
- }
-
- normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
- normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
-
- if (normalized_string && normalized_key)
- {
- case_normalized_string = g_utf8_casefold (normalized_string, -1);
- case_normalized_key = g_utf8_casefold (normalized_key, -1);
-
- if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
- retval = FALSE;
- }
-
- g_value_unset (&transformed);
- g_free (normalized_key);
- g_free (normalized_string);
- g_free (case_normalized_key);
- g_free (case_normalized_string);
-
- return retval;
-}
-
-static gboolean
-pspp_sheet_view_search_iter (GtkTreeModel *model,
- PsppSheetSelection *selection,
- GtkTreeIter *iter,
- const gchar *text,
- gint *count,
- gint n)
-{
- int node = -1;
- GtkTreePath *path;
-
- PsppSheetView *tree_view = pspp_sheet_selection_get_tree_view (selection);
-
- path = gtk_tree_model_get_path (model, iter);
- _pspp_sheet_view_find_node (tree_view, path, &node);
-
- do
- {
- gboolean done = FALSE;
-
- if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
- {
- (*count)++;
- if (*count == n)
- {
- pspp_sheet_view_scroll_to_cell (tree_view, path, NULL,
- TRUE, 0.5, 0.0);
- pspp_sheet_selection_select_iter (selection, iter);
- pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE, 0);
-
- if (path)
- gtk_tree_path_free (path);
-
- return TRUE;
- }
- }
-
-
- do
- {
- node = pspp_sheet_view_node_next (tree_view, node);
-
- if (node >= 0)
- {
- gboolean has_next;
-
- has_next = gtk_tree_model_iter_next (model, iter);
-
- done = TRUE;
- gtk_tree_path_next (path);
-
- /* sanity check */
- TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
- }
- else
- {
- if (path)
- gtk_tree_path_free (path);
-
- /* we've run out of tree, done with this func */
- return FALSE;
- }
- }
- while (!done);
- }
- while (1);
-
- return FALSE;
-}
-
-static void
-pspp_sheet_view_search_init (GtkWidget *entry,
- PsppSheetView *tree_view)
-{
- gint ret;
- gint count = 0;
- const gchar *text;
- GtkTreeIter iter;
- GtkTreeModel *model;
- PsppSheetSelection *selection;
-
- g_return_if_fail (GTK_IS_ENTRY (entry));
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- text = gtk_entry_get_text (GTK_ENTRY (entry));
-
- model = pspp_sheet_view_get_model (tree_view);
- selection = pspp_sheet_view_get_selection (tree_view);
-
- /* search */
- pspp_sheet_selection_unselect_all (selection);
- if (tree_view->priv->typeselect_flush_timeout
- && !tree_view->priv->search_custom_entry_set)
- {
- g_source_remove (tree_view->priv->typeselect_flush_timeout);
- tree_view->priv->typeselect_flush_timeout =
- gdk_threads_add_timeout (PSPP_SHEET_VIEW_SEARCH_DIALOG_TIMEOUT,
- (GSourceFunc) pspp_sheet_view_search_entry_flush_timeout,
- tree_view);
- }
-
- if (*text == '\0')
- return;
-
- if (!gtk_tree_model_get_iter_first (model, &iter))
- return;
-
- ret = pspp_sheet_view_search_iter (model, selection,
- &iter, text,
- &count, 1);
-
- if (ret)
- tree_view->priv->selected_iter = 1;
-}
-
-static void
-pspp_sheet_view_remove_widget (GtkCellEditable *cell_editable,
- PsppSheetView *tree_view)
-{
- if (tree_view->priv->edited_column == NULL)
- return;
-
- _pspp_sheet_view_column_stop_editing (tree_view->priv->edited_column);
- tree_view->priv->edited_column = NULL;
-
- if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
- gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-
- g_signal_handlers_disconnect_by_func (cell_editable,
- pspp_sheet_view_remove_widget,
- tree_view);
- g_signal_handlers_disconnect_by_func (cell_editable,
- pspp_sheet_view_editable_button_press_event,
- tree_view);
- g_signal_handlers_disconnect_by_func (cell_editable,
- pspp_sheet_view_editable_clicked,
- tree_view);
-
- gtk_container_remove (GTK_CONTAINER (tree_view),
- GTK_WIDGET (cell_editable));
-
- /* FIXME should only redraw a single node */
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-}
-
-static gboolean
-pspp_sheet_view_start_editing (PsppSheetView *tree_view,
- GtkTreePath *cursor_path)
-{
- GtkTreeIter iter;
- GdkRectangle background_area;
- GdkRectangle cell_area;
- GtkCellEditable *editable_widget = NULL;
- gchar *path_string;
- guint flags = 0; /* can be 0, as the flags are primarily for rendering */
- gint retval = FALSE;
- int cursor_node;
-
- g_assert (tree_view->priv->focus_column);
-
- if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
- return FALSE;
-
- _pspp_sheet_view_find_node (tree_view, cursor_path, &cursor_node);
- if (cursor_node < 0)
- return FALSE;
-
- path_string = gtk_tree_path_to_string (cursor_path);
- gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
-
- pspp_sheet_view_column_cell_set_cell_data (tree_view->priv->focus_column,
- tree_view->priv->model,
- &iter);
- pspp_sheet_view_get_background_area (tree_view,
- cursor_path,
- tree_view->priv->focus_column,
- &background_area);
- pspp_sheet_view_get_cell_area (tree_view,
- cursor_path,
- tree_view->priv->focus_column,
- &cell_area);
-
- if (_pspp_sheet_view_column_cell_event (tree_view->priv->focus_column,
- &editable_widget,
- NULL,
- path_string,
- &background_area,
- &cell_area,
- flags))
- {
- retval = TRUE;
- if (editable_widget != NULL)
- {
- gint left, right;
- GdkRectangle area;
- GtkCellRenderer *cell;
-
- area = cell_area;
- cell = _pspp_sheet_view_column_get_edited_cell (tree_view->priv->focus_column);
-
- _pspp_sheet_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
-
- area.x += left;
- area.width -= right + left;
-
- pspp_sheet_view_real_start_editing (tree_view,
- tree_view->priv->focus_column,
- cursor_path,
- editable_widget,
- &area,
- NULL,
- flags);
- }
-
- }
- g_free (path_string);
- return retval;
-}
-
-static gboolean
-pspp_sheet_view_editable_button_press_event (GtkWidget *widget,
- GdkEventButton *event,
- PsppSheetView *sheet_view)
-{
- gint node;
-
- node = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
- "pspp-sheet-view-node"));
- return pspp_sheet_view_row_head_clicked (sheet_view,
- node,
- sheet_view->priv->edited_column,
- event);
-}
-
-static void
-pspp_sheet_view_editable_clicked (GtkButton *button,
- PsppSheetView *sheet_view)
-{
- pspp_sheet_view_editable_button_press_event (GTK_WIDGET (button), NULL,
- sheet_view);
-}
-
-static gboolean
-is_all_selected (GtkWidget *widget)
-{
- GtkEntryBuffer *buffer;
- gint start_pos, end_pos;
-
- if (!GTK_IS_ENTRY (widget))
- return FALSE;
-
- buffer = gtk_entry_get_buffer (GTK_ENTRY (widget));
- return (gtk_editable_get_selection_bounds (GTK_EDITABLE (widget),
- &start_pos, &end_pos)
- && start_pos == 0
- && end_pos == gtk_entry_buffer_get_length (buffer));
-}
-
-static gboolean
-is_at_left (GtkWidget *widget)
-{
- return (GTK_IS_ENTRY (widget)
- && gtk_editable_get_position (GTK_EDITABLE (widget)) == 0);
-}
-
-static gboolean
-is_at_right (GtkWidget *widget)
-{
- GtkEntryBuffer *buffer;
- gint length;
-
- if (!GTK_IS_ENTRY (widget))
- return FALSE;
-
- buffer = gtk_entry_get_buffer (GTK_ENTRY (widget));
- length = gtk_entry_buffer_get_length (buffer);
- return gtk_editable_get_position (GTK_EDITABLE (widget)) == length;
-}
-
-static gboolean
-pspp_sheet_view_event (GtkWidget *widget,
- GdkEventKey *event,
- PsppSheetView *tree_view)
-{
- PsppSheetViewColumn *column;
- GtkTreePath *path;
- gboolean handled;
- gboolean cancel;
- guint keyval;
- gint row;
-
- /* Intercept only key press events.
- It would make sense to use "key-press-event" instead of "event", but
- GtkEntry attaches its own signal handler to "key-press-event" that runs
- before ours and overrides our desired behavior for GDK_Up and GDK_Down.
- */
- if (event->type != GDK_KEY_PRESS)
- return FALSE;
-
- keyval = event->keyval;
- cancel = FALSE;
- switch (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK | GDK_MOD1_MASK))
- {
- case 0:
- switch (event->keyval)
- {
- case GDK_Left: case GDK_KP_Left:
- case GDK_Home: case GDK_KP_Home:
- if (!is_all_selected (widget) && !is_at_left (widget))
- return FALSE;
- break;
-
- case GDK_Right: case GDK_KP_Right:
- case GDK_End: case GDK_KP_End:
- if (!is_all_selected (widget) && !is_at_right (widget))
- return FALSE;
- break;
-
- case GDK_Up: case GDK_KP_Up:
- case GDK_Down: case GDK_KP_Down:
- break;
-
- case GDK_Page_Up: case GDK_KP_Page_Up:
- case GDK_Page_Down: case GDK_KP_Page_Down:
- break;
-
- case GDK_Escape:
- cancel = TRUE;
- break;
-
- case GDK_Return:
- keyval = GDK_Down;
- break;
-
- case GDK_Tab: case GDK_KP_Tab:
- case GDK_ISO_Left_Tab:
- keyval = GDK_Tab;
- break;
-
- default:
- return FALSE;
- }
- break;
-
- case GDK_SHIFT_MASK:
- switch (event->keyval)
- {
- case GDK_Tab:
- case GDK_ISO_Left_Tab:
- keyval = GDK_Tab;
- break;
-
- default:
- return FALSE;
- }
- break;
-
- case GDK_CONTROL_MASK:
- switch (event->keyval)
- {
- case GDK_Left: case GDK_KP_Left:
- if (!is_all_selected (widget) && !is_at_left (widget))
- return FALSE;
- break;
-
- case GDK_Right: case GDK_KP_Right:
- if (!is_all_selected (widget) && !is_at_right (widget))
- return FALSE;
- break;
-
- case GDK_Up: case GDK_KP_Up:
- case GDK_Down: case GDK_KP_Down:
- break;
-
- default:
- return FALSE;
- }
- break;
-
- default:
- return FALSE;
- }
-
- row = tree_view->priv->edited_row;
- column = tree_view->priv->edited_column;
- path = gtk_tree_path_new_from_indices (row, -1);
-
- pspp_sheet_view_stop_editing (tree_view, cancel);
- gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-
- pspp_sheet_view_set_cursor (tree_view, path, column, FALSE);
- gtk_tree_path_free (path);
-
- handled = gtk_binding_set_activate (edit_bindings, keyval, event->state,
- G_OBJECT (tree_view));
- if (handled)
- g_signal_stop_emission_by_name (widget, "event");
-
- pspp_sheet_view_get_cursor (tree_view, &path, NULL);
- pspp_sheet_view_start_editing (tree_view, path);
- gtk_tree_path_free (path);
-
- return handled;
-}
-
-static void
-pspp_sheet_view_override_cell_keypresses (GtkWidget *widget,
- gpointer data)
-{
- PsppSheetView *sheet_view = data;
-
- g_signal_connect (widget, "event",
- G_CALLBACK (pspp_sheet_view_event),
- sheet_view);
-
- if (GTK_IS_CONTAINER (widget))
- gtk_container_foreach (GTK_CONTAINER (widget),
- pspp_sheet_view_override_cell_keypresses,
- data);
-}
-
-static void
-pspp_sheet_view_real_start_editing (PsppSheetView *tree_view,
- PsppSheetViewColumn *column,
- GtkTreePath *path,
- GtkCellEditable *cell_editable,
- GdkRectangle *cell_area,
- GdkEvent *event,
- guint flags)
-{
- PsppSheetSelectionMode mode = pspp_sheet_selection_get_mode (tree_view->priv->selection);
- gint pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
- gint row;
-
- g_return_if_fail (gtk_tree_path_get_depth (path) == 1);
-
- tree_view->priv->edited_column = column;
- _pspp_sheet_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
-
- row = gtk_tree_path_get_indices (path)[0];
- tree_view->priv->edited_row = row;
- pspp_sheet_view_real_set_cursor (tree_view, path, FALSE, TRUE, 0);
- cell_area->y += pre_val - (int)gtk_adjustment_get_value (tree_view->priv->vadjustment);
-
- pspp_sheet_selection_unselect_all_columns (tree_view->priv->selection);
- pspp_sheet_selection_select_column (tree_view->priv->selection, column);
- tree_view->priv->anchor_column = column;
-
- PSPP_SHEET_VIEW_SET_FLAG (tree_view, PSPP_SHEET_VIEW_DRAW_KEYFOCUS);
-
- pspp_sheet_view_put (tree_view,
- GTK_WIDGET (cell_editable),
- path,
- column);
-
- gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
- (GdkEvent *)event);
-
- gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
- g_signal_connect (cell_editable, "remove-widget",
- G_CALLBACK (pspp_sheet_view_remove_widget), tree_view);
- if (mode == PSPP_SHEET_SELECTION_RECTANGLE && column->row_head &&
- GTK_IS_BUTTON (cell_editable))
- {
- g_signal_connect (cell_editable, "button-press-event",
- G_CALLBACK (pspp_sheet_view_editable_button_press_event),
- tree_view);
- g_object_set_data (G_OBJECT (cell_editable), "pspp-sheet-view-node",
- GINT_TO_POINTER (row));
- g_signal_connect (cell_editable, "clicked",
- G_CALLBACK (pspp_sheet_view_editable_clicked),
- tree_view);
- }
-
- pspp_sheet_view_override_cell_keypresses (GTK_WIDGET (cell_editable),
- tree_view);
-}
-
-void
-pspp_sheet_view_stop_editing (PsppSheetView *tree_view,
- gboolean cancel_editing)
-{
- PsppSheetViewColumn *column;
- GtkCellRenderer *cell;
-
- if (tree_view->priv->edited_column == NULL)
- return;
-
- /*
- * This is very evil. We need to do this, because
- * gtk_cell_editable_editing_done may trigger pspp_sheet_view_row_changed
- * later on. If pspp_sheet_view_row_changed notices
- * tree_view->priv->edited_column != NULL, it'll call
- * pspp_sheet_view_stop_editing again. Bad things will happen then.
- *
- * Please read that again if you intend to modify anything here.
- */
-
- column = tree_view->priv->edited_column;
- tree_view->priv->edited_column = NULL;
-
- cell = _pspp_sheet_view_column_get_edited_cell (column);
- gtk_cell_renderer_stop_editing (cell, cancel_editing);
-
- if (!cancel_editing)
- gtk_cell_editable_editing_done (column->editable_widget);
-
- tree_view->priv->edited_column = column;
-
- gtk_cell_editable_remove_widget (column->editable_widget);
-}
-
-
-/**
- * pspp_sheet_view_set_hover_selection:
- * @tree_view: a #PsppSheetView
- * @hover: %TRUE to enable hover selection mode
- *
- * Enables of disables the hover selection mode of @tree_view.
- * Hover selection makes the selected row follow the pointer.
- * Currently, this works only for the selection modes
- * %PSPP_SHEET_SELECTION_SINGLE and %PSPP_SHEET_SELECTION_BROWSE.
- *
- * Since: 2.6
- **/
-void
-pspp_sheet_view_set_hover_selection (PsppSheetView *tree_view,
- gboolean hover)
-{
- hover = hover != FALSE;
-
- if (hover != tree_view->priv->hover_selection)
- {
- tree_view->priv->hover_selection = hover;
-
- g_object_notify (G_OBJECT (tree_view), "hover-selection");
- }
-}
-
-/**
- * pspp_sheet_view_get_hover_selection:
- * @tree_view: a #PsppSheetView
- *
- * Returns whether hover selection mode is turned on for @tree_view.
- *
- * Return value: %TRUE if @tree_view is in hover selection mode
- *
- * Since: 2.6
- **/
-gboolean
-pspp_sheet_view_get_hover_selection (PsppSheetView *tree_view)
-{
- return tree_view->priv->hover_selection;
-}
-
-/**
- * pspp_sheet_view_set_rubber_banding:
- * @tree_view: a #PsppSheetView
- * @enable: %TRUE to enable rubber banding
- *
- * Enables or disables rubber banding in @tree_view. If the selection mode is
- * #PSPP_SHEET_SELECTION_MULTIPLE or #PSPP_SHEET_SELECTION_RECTANGLE, rubber
- * banding will allow the user to select multiple rows by dragging the mouse.
- *
- * Since: 2.10
- **/
-void
-pspp_sheet_view_set_rubber_banding (PsppSheetView *tree_view,
- gboolean enable)
-{
- enable = enable != FALSE;
-
- if (enable != tree_view->priv->rubber_banding_enable)
- {
- tree_view->priv->rubber_banding_enable = enable;
-
- g_object_notify (G_OBJECT (tree_view), "rubber-banding");
- }
-}
-
-/**
- * pspp_sheet_view_get_rubber_banding:
- * @tree_view: a #PsppSheetView
- *
- * Returns whether rubber banding is turned on for @tree_view. If the
- * selection mode is #PSPP_SHEET_SELECTION_MULTIPLE or
- * #PSPP_SHEET_SELECTION_RECTANGLE, rubber banding will allow the user to
- * select multiple rows by dragging the mouse.
- *
- * Return value: %TRUE if rubber banding in @tree_view is enabled.
- *
- * Since: 2.10
- **/
-gboolean
-pspp_sheet_view_get_rubber_banding (PsppSheetView *tree_view)
-{
- return tree_view->priv->rubber_banding_enable;
-}
-
-/**
- * pspp_sheet_view_is_rubber_banding_active:
- * @tree_view: a #PsppSheetView
- *
- * Returns whether a rubber banding operation is currently being done
- * in @tree_view.
- *
- * Return value: %TRUE if a rubber banding operation is currently being
- * done in @tree_view.
- *
- * Since: 2.12
- **/
-gboolean
-pspp_sheet_view_is_rubber_banding_active (PsppSheetView *tree_view)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
-
- if (tree_view->priv->rubber_banding_enable
- && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
- return TRUE;
-
- return FALSE;
-}
-
-static void
-pspp_sheet_view_grab_notify (GtkWidget *widget,
- gboolean was_grabbed)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-
- tree_view->priv->in_grab = !was_grabbed;
-
- if (!was_grabbed)
- {
- tree_view->priv->pressed_button = -1;
-
- if (tree_view->priv->rubber_band_status)
- pspp_sheet_view_stop_rubber_band (tree_view);
- }
-}
-
-static void
-pspp_sheet_view_state_changed (GtkWidget *widget,
- GtkStateType previous_state)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-
- if (gtk_widget_get_realized (widget))
- {
- GtkStyle *style = gtk_widget_get_style (widget);
- gdk_window_set_background (tree_view->priv->bin_window, &style->base[gtk_widget_get_state (widget)]);
- }
-
- gtk_widget_queue_draw (widget);
-}
-
-/**
- * pspp_sheet_view_get_grid_lines:
- * @tree_view: a #PsppSheetView
- *
- * Returns which grid lines are enabled in @tree_view.
- *
- * Return value: a #PsppSheetViewGridLines value indicating which grid lines
- * are enabled.
- *
- * Since: 2.10
- */
-PsppSheetViewGridLines
-pspp_sheet_view_get_grid_lines (PsppSheetView *tree_view)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), 0);
-
- return tree_view->priv->grid_lines;
-}
-
-/**
- * pspp_sheet_view_set_grid_lines:
- * @tree_view: a #PsppSheetView
- * @grid_lines: a #PsppSheetViewGridLines value indicating which grid lines to
- * enable.
- *
- * Sets which grid lines to draw in @tree_view.
- *
- * Since: 2.10
- */
-void
-pspp_sheet_view_set_grid_lines (PsppSheetView *tree_view,
- PsppSheetViewGridLines grid_lines)
-{
- PsppSheetViewPrivate *priv;
- PsppSheetViewGridLines old_grid_lines;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- priv = tree_view->priv;
-
- old_grid_lines = priv->grid_lines;
- priv->grid_lines = grid_lines;
-
- if (old_grid_lines != grid_lines)
- {
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-
- g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
- }
-}
-
-/**
- * pspp_sheet_view_get_special_cells:
- * @tree_view: a #PsppSheetView
- *
- * Returns which grid lines are enabled in @tree_view.
- *
- * Return value: a #PsppSheetViewSpecialCells value indicating whether rows in
- * the sheet view contain special cells.
- */
-PsppSheetViewSpecialCells
-pspp_sheet_view_get_special_cells (PsppSheetView *tree_view)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), 0);
-
- return tree_view->priv->special_cells;
-}
-
-/**
- * pspp_sheet_view_set_special_cells:
- * @tree_view: a #PsppSheetView
- * @special_cells: a #PsppSheetViewSpecialCells value indicating whether rows in
- * the sheet view contain special cells.
- *
- * Sets whether rows in the sheet view contain special cells, controlling the
- * rendering of row selections.
- */
-void
-pspp_sheet_view_set_special_cells (PsppSheetView *tree_view,
- PsppSheetViewSpecialCells special_cells)
-{
- PsppSheetViewPrivate *priv;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- priv = tree_view->priv;
-
- if (priv->special_cells != special_cells)
- {
- priv->special_cells = special_cells;
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
- g_object_notify (G_OBJECT (tree_view), "special-cells");
- }
-}
-
-int
-pspp_sheet_view_get_fixed_height (const PsppSheetView *tree_view)
-{
- /* XXX (re)calculate fixed_height if necessary */
- return tree_view->priv->fixed_height;
-}
-
-void
-pspp_sheet_view_set_fixed_height (PsppSheetView *tree_view,
- int fixed_height)
-{
- g_return_if_fail (fixed_height > 0);
-
- if (tree_view->priv->fixed_height != fixed_height)
- {
- tree_view->priv->fixed_height = fixed_height;
- g_object_notify (G_OBJECT (tree_view), "fixed-height");
- }
- if (!tree_view->priv->fixed_height_set)
- {
- tree_view->priv->fixed_height_set = TRUE;
- g_object_notify (G_OBJECT (tree_view), "fixed-height-set");
- }
-}
-
-/**
- * pspp_sheet_view_set_tooltip_row:
- * @tree_view: a #PsppSheetView
- * @tooltip: a #GtkTooltip
- * @path: a #GtkTreePath
- *
- * Sets the tip area of @tooltip to be the area covered by the row at @path.
- * See also pspp_sheet_view_set_tooltip_column() for a simpler alternative.
- * See also gtk_tooltip_set_tip_area().
- *
- * Since: 2.12
- */
-void
-pspp_sheet_view_set_tooltip_row (PsppSheetView *tree_view,
- GtkTooltip *tooltip,
- GtkTreePath *path)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
- g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
-
- pspp_sheet_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
-}
-
-/**
- * pspp_sheet_view_set_tooltip_cell:
- * @tree_view: a #PsppSheetView
- * @tooltip: a #GtkTooltip
- * @path: (allow-none): a #GtkTreePath or %NULL
- * @column: (allow-none): a #PsppSheetViewColumn or %NULL
- * @cell: (allow-none): a #GtkCellRenderer or %NULL
- *
- * Sets the tip area of @tooltip to the area @path, @column and @cell have
- * in common. For example if @path is %NULL and @column is set, the tip
- * area will be set to the full area covered by @column. See also
- * gtk_tooltip_set_tip_area().
- *
- * See also pspp_sheet_view_set_tooltip_column() for a simpler alternative.
- *
- * Since: 2.12
- */
-void
-pspp_sheet_view_set_tooltip_cell (PsppSheetView *tree_view,
- GtkTooltip *tooltip,
- GtkTreePath *path,
- PsppSheetViewColumn *column,
- GtkCellRenderer *cell)
-{
- GdkRectangle rect;
-
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
- g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
- g_return_if_fail (column == NULL || PSPP_IS_SHEET_VIEW_COLUMN (column));
- g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
-
- /* Determine x values. */
- if (column && cell)
- {
- GdkRectangle tmp;
- gint start, width;
-
- pspp_sheet_view_get_cell_area (tree_view, path, column, &tmp);
- pspp_sheet_view_column_cell_get_position (column, cell, &start, &width);
-
- pspp_sheet_view_convert_bin_window_to_widget_coords (tree_view,
- tmp.x + start, 0,
- &rect.x, NULL);
- rect.width = width;
- }
- else if (column)
- {
- GdkRectangle tmp;
-
- pspp_sheet_view_get_background_area (tree_view, NULL, column, &tmp);
- pspp_sheet_view_convert_bin_window_to_widget_coords (tree_view,
- tmp.x, 0,
- &rect.x, NULL);
- rect.width = tmp.width;
- }
- else
- {
- GtkAllocation allocation;
- gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
- rect.x = 0;
- rect.width = allocation.width;
- }
-
- /* Determine y values. */
- if (path)
- {
- GdkRectangle tmp;
-
- pspp_sheet_view_get_background_area (tree_view, path, NULL, &tmp);
- pspp_sheet_view_convert_bin_window_to_widget_coords (tree_view,
- 0, tmp.y,
- NULL, &rect.y);
- rect.height = tmp.height;
- }
- else
- {
- rect.y = 0;
- rect.height = gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
- }
-
- gtk_tooltip_set_tip_area (tooltip, &rect);
-}
-
-/**
- * pspp_sheet_view_get_tooltip_context:
- * @tree_view: a #PsppSheetView
- * @x: the x coordinate (relative to widget coordinates)
- * @y: the y coordinate (relative to widget coordinates)
- * @keyboard_tip: whether this is a keyboard tooltip or not
- * @model: (allow-none): a pointer to receive a #GtkTreeModel or %NULL
- * @path: (allow-none): a pointer to receive a #GtkTreePath or %NULL
- * @iter: (allow-none): a pointer to receive a #GtkTreeIter or %NULL
- *
- * This function is supposed to be used in a #GtkWidget::query-tooltip
- * signal handler for #PsppSheetView. The @x, @y and @keyboard_tip values
- * which are received in the signal handler, should be passed to this
- * function without modification.
- *
- * The return value indicates whether there is a tree view row at the given
- * coordinates (%TRUE) or not (%FALSE) for mouse tooltips. For keyboard
- * tooltips the row returned will be the cursor row. When %TRUE, then any of
- * @model, @path and @iter which have been provided will be set to point to
- * that row and the corresponding model. @x and @y will always be converted
- * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
- *
- * Return value: whether or not the given tooltip context points to a row.
- *
- * Since: 2.12
- */
-gboolean
-pspp_sheet_view_get_tooltip_context (PsppSheetView *tree_view,
- gint *x,
- gint *y,
- gboolean keyboard_tip,
- GtkTreeModel **model,
- GtkTreePath **path,
- GtkTreeIter *iter)
-{
- GtkTreePath *tmppath = NULL;
-
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), FALSE);
- g_return_val_if_fail (x != NULL, FALSE);
- g_return_val_if_fail (y != NULL, FALSE);
-
- if (keyboard_tip)
- {
- pspp_sheet_view_get_cursor (tree_view, &tmppath, NULL);
-
- if (!tmppath)
- return FALSE;
- }
- else
- {
- pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
- x, y);
-
- if (!pspp_sheet_view_get_path_at_pos (tree_view, *x, *y,
- &tmppath, NULL, NULL, NULL))
- return FALSE;
- }
-
- if (model)
- *model = pspp_sheet_view_get_model (tree_view);
-
- if (iter)
- gtk_tree_model_get_iter (pspp_sheet_view_get_model (tree_view),
- iter, tmppath);
-
- if (path)
- *path = tmppath;
- else
- gtk_tree_path_free (tmppath);
-
- return TRUE;
-}
-
-static gboolean
-pspp_sheet_view_set_tooltip_query_cb (GtkWidget *widget,
- gint x,
- gint y,
- gboolean keyboard_tip,
- GtkTooltip *tooltip,
- gpointer data)
-{
- GValue value = { 0, };
- GValue transformed = { 0, };
- GtkTreeIter iter;
- GtkTreePath *path;
- GtkTreeModel *model;
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
-
- if (!pspp_sheet_view_get_tooltip_context (PSPP_SHEET_VIEW (widget),
- &x, &y,
- keyboard_tip,
- &model, &path, &iter))
- return FALSE;
-
- gtk_tree_model_get_value (model, &iter,
- tree_view->priv->tooltip_column, &value);
-
- g_value_init (&transformed, G_TYPE_STRING);
-
- if (!g_value_transform (&value, &transformed))
- {
- g_value_unset (&value);
- gtk_tree_path_free (path);
-
- return FALSE;
- }
-
- g_value_unset (&value);
-
- if (!g_value_get_string (&transformed))
- {
- g_value_unset (&transformed);
- gtk_tree_path_free (path);
-
- return FALSE;
- }
-
- gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
- pspp_sheet_view_set_tooltip_row (tree_view, tooltip, path);
-
- gtk_tree_path_free (path);
- g_value_unset (&transformed);
-
- return TRUE;
-}
-
-/**
- * pspp_sheet_view_set_tooltip_column:
- * @tree_view: a #PsppSheetView
- * @column: an integer, which is a valid column number for @tree_view's model
- *
- * If you only plan to have simple (text-only) tooltips on full rows, you
- * can use this function to have #PsppSheetView handle these automatically
- * for you. @column should be set to the column in @tree_view's model
- * containing the tooltip texts, or -1 to disable this feature.
- *
- * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
- * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
- *
- * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
- * so &, <, etc have to be escaped in the text.
- *
- * Since: 2.12
- */
-void
-pspp_sheet_view_set_tooltip_column (PsppSheetView *tree_view,
- gint column)
-{
- g_return_if_fail (PSPP_IS_SHEET_VIEW (tree_view));
-
- if (column == tree_view->priv->tooltip_column)
- return;
-
- if (column == -1)
- {
- g_signal_handlers_disconnect_by_func (tree_view,
- pspp_sheet_view_set_tooltip_query_cb,
- NULL);
- gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
- }
- else
- {
- if (tree_view->priv->tooltip_column == -1)
- {
- g_signal_connect (tree_view, "query-tooltip",
- G_CALLBACK (pspp_sheet_view_set_tooltip_query_cb), NULL);
- gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
- }
- }
-
- tree_view->priv->tooltip_column = column;
- g_object_notify (G_OBJECT (tree_view), "tooltip-column");
-}
-
-/**
- * pspp_sheet_view_get_tooltip_column:
- * @tree_view: a #PsppSheetView
- *
- * Returns the column of @tree_view's model which is being used for
- * displaying tooltips on @tree_view's rows.
- *
- * Return value: the index of the tooltip column that is currently being
- * used, or -1 if this is disabled.
- *
- * Since: 2.12
- */
-gint
-pspp_sheet_view_get_tooltip_column (PsppSheetView *tree_view)
-{
- g_return_val_if_fail (PSPP_IS_SHEET_VIEW (tree_view), 0);
-
- return tree_view->priv->tooltip_column;
-}
-
-gboolean
-_gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint,
- GValue *return_accu,
- const GValue *handler_return,
- gpointer dummy)
-{
- gboolean continue_emission;
- gboolean signal_handled;
-
- signal_handled = g_value_get_boolean (handler_return);
- g_value_set_boolean (return_accu, signal_handled);
- continue_emission = !signal_handled;
-
- return continue_emission;
-}
-
-
-GType
-pspp_sheet_view_grid_lines_get_type (void)
-{
- static GType etype = 0;
- if (G_UNLIKELY(etype == 0)) {
- static const GEnumValue values[] = {
- { PSPP_SHEET_VIEW_GRID_LINES_NONE, "PSPP_SHEET_VIEW_GRID_LINES_NONE", "none" },
- { PSPP_SHEET_VIEW_GRID_LINES_HORIZONTAL, "PSPP_SHEET_VIEW_GRID_LINES_HORIZONTAL", "horizontal" },
- { PSPP_SHEET_VIEW_GRID_LINES_VERTICAL, "PSPP_SHEET_VIEW_GRID_LINES_VERTICAL", "vertical" },
- { PSPP_SHEET_VIEW_GRID_LINES_BOTH, "PSPP_SHEET_VIEW_GRID_LINES_BOTH", "both" },
- { 0, NULL, NULL }
- };
- etype = g_enum_register_static (g_intern_static_string ("PsppSheetViewGridLines"), values);
- }
- return etype;
-}
-
-GType
-pspp_sheet_view_special_cells_get_type (void)
-{
- static GType etype = 0;
- if (G_UNLIKELY(etype == 0)) {
- static const GEnumValue values[] = {
- { PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT, "PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT", "detect" },
- { PSPP_SHEET_VIEW_SPECIAL_CELLS_YES, "PSPP_SHEET_VIEW_SPECIAL_CELLS_YES", "yes" },
- { PSPP_SHEET_VIEW_SPECIAL_CELLS_NO, "PSPP_SHEET_VIEW_SPECIAL_CELLS_NO", "no" },
- { 0, NULL, NULL }
- };
- etype = g_enum_register_static (g_intern_static_string ("PsppSheetViewSpecialCells"), values);
- }
- return etype;
-}
+++ /dev/null
-/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2011, 2012, 2013 Free Software Foundation, Inc.
-
- 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/>. */
-
-/* gtktreeview.h
- * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * 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.
- */
-
-#ifndef __PSPP_SHEET_VIEW_H__
-#define __PSPP_SHEET_VIEW_H__
-
-#include <gtk/gtk.h>
-#include "ui/gui/pspp-sheet-view-column.h"
-
-G_BEGIN_DECLS
-
-
-typedef enum
-{
- PSPP_SHEET_VIEW_GRID_LINES_NONE,
- PSPP_SHEET_VIEW_GRID_LINES_HORIZONTAL,
- PSPP_SHEET_VIEW_GRID_LINES_VERTICAL,
- PSPP_SHEET_VIEW_GRID_LINES_BOTH
-} PsppSheetViewGridLines;
-
-GType pspp_sheet_view_grid_lines_get_type (void) G_GNUC_CONST;
-#define PSPP_TYPE_SHEET_VIEW_GRID_LINES (pspp_sheet_view_grid_lines_get_type ())
-
-/* A "special cell" is a cell that is editable or activatable. When a row that
- * contains a special cell is selected, the cursor is drawn around a single
- * cell; when other rows are selected, the cursor is drawn around the entire
- * row.
- *
- * With the default of "detect", whether a given row contains a special cell is
- * detected automatically. This is the best choice most of the time. For
- * sheet views that contain more than 100 columns, an explicit "yes" or "no"
- * improves performance. */
-typedef enum
-{
- PSPP_SHEET_VIEW_SPECIAL_CELLS_DETECT,
- PSPP_SHEET_VIEW_SPECIAL_CELLS_YES,
- PSPP_SHEET_VIEW_SPECIAL_CELLS_NO,
-} PsppSheetViewSpecialCells;
-
-GType pspp_sheet_view_special_cells_get_type (void) G_GNUC_CONST;
-#define PSPP_TYPE_SHEET_VIEW_SPECIAL_CELLS (pspp_sheet_view_special_cells_get_type ())
-
-typedef enum
-{
- /* drop before/after this row */
- PSPP_SHEET_VIEW_DROP_BEFORE,
- PSPP_SHEET_VIEW_DROP_AFTER,
- /* drop as a child of this row (with fallback to before or after
- * if into is not possible)
- */
- PSPP_SHEET_VIEW_DROP_INTO_OR_BEFORE,
- PSPP_SHEET_VIEW_DROP_INTO_OR_AFTER
-} PsppSheetViewDropPosition;
-
-typedef enum
-{
- PSPP_SHEET_SELECT_MODE_TOGGLE = 1 << 0,
- PSPP_SHEET_SELECT_MODE_EXTEND = 1 << 1
-}
-PsppSheetSelectMode;
-
-#define PSPP_TYPE_SHEET_VIEW (pspp_sheet_view_get_type ())
-#define PSPP_SHEET_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PSPP_TYPE_SHEET_VIEW, PsppSheetView))
-#define PSPP_SHEET_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PSPP_TYPE_SHEET_VIEW, PsppSheetViewClass))
-#define PSPP_IS_SHEET_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPP_TYPE_SHEET_VIEW))
-#define PSPP_IS_SHEET_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPP_TYPE_SHEET_VIEW))
-#define PSPP_SHEET_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PSPP_TYPE_SHEET_VIEW, PsppSheetViewClass))
-
-typedef struct _PsppSheetView PsppSheetView;
-typedef struct _PsppSheetViewClass PsppSheetViewClass;
-typedef struct _PsppSheetViewPrivate PsppSheetViewPrivate;
-typedef struct _PsppSheetSelection PsppSheetSelection;
-typedef struct _PsppSheetSelectionClass PsppSheetSelectionClass;
-
-struct _PsppSheetView
-{
- GtkContainer parent;
-
- PsppSheetViewPrivate *PSEAL (priv);
-
- gboolean dispose_has_run ;
-};
-
-struct _PsppSheetViewClass
-{
- GtkContainerClass parent_class;
-
- void (* set_scroll_adjustments) (PsppSheetView *tree_view,
- GtkAdjustment *hadjustment,
- GtkAdjustment *vadjustment);
- void (* row_activated) (PsppSheetView *tree_view,
- GtkTreePath *path,
- PsppSheetViewColumn *column);
- void (* columns_changed) (PsppSheetView *tree_view);
- void (* cursor_changed) (PsppSheetView *tree_view);
-
- /* Key Binding signals */
- gboolean (* move_cursor) (PsppSheetView *tree_view,
- GtkMovementStep step,
- gint count);
- gboolean (* select_all) (PsppSheetView *tree_view);
- gboolean (* unselect_all) (PsppSheetView *tree_view);
- gboolean (* select_cursor_row) (PsppSheetView *tree_view,
- gboolean start_editing,
- PsppSheetSelectMode mode);
- gboolean (* toggle_cursor_row) (PsppSheetView *tree_view);
- gboolean (* select_cursor_parent) (PsppSheetView *tree_view);
- gboolean (* start_interactive_search) (PsppSheetView *tree_view);
-
- /* Padding for future expansion */
- void (*_gtk_reserved0) (void);
- void (*_gtk_reserved1) (void);
- void (*_gtk_reserved2) (void);
- void (*_gtk_reserved3) (void);
- void (*_gtk_reserved4) (void);
-};
-
-
-typedef gboolean (* PsppSheetViewColumnDropFunc) (PsppSheetView *tree_view,
- PsppSheetViewColumn *column,
- PsppSheetViewColumn *prev_column,
- PsppSheetViewColumn *next_column,
- gpointer data);
-typedef void (* PsppSheetViewMappingFunc) (PsppSheetView *tree_view,
- GtkTreePath *path,
- gpointer user_data);
-typedef gboolean (*PsppSheetViewSearchEqualFunc) (GtkTreeModel *model,
- gint column,
- const gchar *key,
- GtkTreeIter *iter,
- gpointer search_data);
-typedef void (*PsppSheetViewSearchPositionFunc) (PsppSheetView *tree_view,
- GtkWidget *search_dialog,
- gpointer user_data);
-
-
-/* Creators */
-GType pspp_sheet_view_get_type (void) G_GNUC_CONST;
-GtkWidget *pspp_sheet_view_new (void);
-GtkWidget *pspp_sheet_view_new_with_model (GtkTreeModel *model);
-
-/* Accessors */
-GtkTreeModel *pspp_sheet_view_get_model (PsppSheetView *tree_view);
-void pspp_sheet_view_set_model (PsppSheetView *tree_view,
- GtkTreeModel *model);
-PsppSheetSelection *pspp_sheet_view_get_selection (PsppSheetView *tree_view);
-GtkAdjustment *pspp_sheet_view_get_hadjustment (PsppSheetView *tree_view);
-void pspp_sheet_view_set_hadjustment (PsppSheetView *tree_view,
- GtkAdjustment *adjustment);
-GtkAdjustment *pspp_sheet_view_get_vadjustment (PsppSheetView *tree_view);
-void pspp_sheet_view_set_vadjustment (PsppSheetView *tree_view,
- GtkAdjustment *adjustment);
-gboolean pspp_sheet_view_get_headers_visible (PsppSheetView *tree_view);
-void pspp_sheet_view_set_headers_visible (PsppSheetView *tree_view,
- gboolean headers_visible);
-void pspp_sheet_view_columns_autosize (PsppSheetView *tree_view);
-gboolean pspp_sheet_view_get_headers_clickable (PsppSheetView *tree_view);
-void pspp_sheet_view_set_headers_clickable (PsppSheetView *tree_view,
- gboolean setting);
-void pspp_sheet_view_set_rules_hint (PsppSheetView *tree_view,
- gboolean setting);
-gboolean pspp_sheet_view_get_rules_hint (PsppSheetView *tree_view);
-
-/* Column funtions */
-gint pspp_sheet_view_append_column (PsppSheetView *tree_view,
- PsppSheetViewColumn *column);
-gint pspp_sheet_view_remove_column (PsppSheetView *tree_view,
- PsppSheetViewColumn *column);
-gint pspp_sheet_view_insert_column (PsppSheetView *tree_view,
- PsppSheetViewColumn *column,
- gint position);
-gint pspp_sheet_view_insert_column_with_attributes (PsppSheetView *tree_view,
- gint position,
- const gchar *title,
- GtkCellRenderer *cell,
- ...) G_GNUC_NULL_TERMINATED;
-gint pspp_sheet_view_insert_column_with_data_func (PsppSheetView *tree_view,
- gint position,
- const gchar *title,
- GtkCellRenderer *cell,
- PsppSheetCellDataFunc func,
- gpointer data,
- GDestroyNotify dnotify);
-PsppSheetViewColumn *pspp_sheet_view_get_column (PsppSheetView *tree_view,
- gint n);
-GList *pspp_sheet_view_get_columns (PsppSheetView *tree_view);
-void pspp_sheet_view_move_column_after (PsppSheetView *tree_view,
- PsppSheetViewColumn *column,
- PsppSheetViewColumn *base_column);
-void pspp_sheet_view_set_column_drag_function (PsppSheetView *tree_view,
- PsppSheetViewColumnDropFunc func,
- gpointer user_data,
- GDestroyNotify destroy);
-
-/* Actions */
-void pspp_sheet_view_scroll_to_point (PsppSheetView *tree_view,
- gint tree_x,
- gint tree_y);
-void pspp_sheet_view_scroll_to_cell (PsppSheetView *tree_view,
- GtkTreePath *path,
- PsppSheetViewColumn *column,
- gboolean use_align,
- gfloat row_align,
- gfloat col_align);
-void pspp_sheet_view_row_activated (PsppSheetView *tree_view,
- GtkTreePath *path,
- PsppSheetViewColumn *column);
-void pspp_sheet_view_set_reorderable (PsppSheetView *tree_view,
- gboolean reorderable);
-gboolean pspp_sheet_view_get_reorderable (PsppSheetView *tree_view);
-void pspp_sheet_view_set_cursor (PsppSheetView *tree_view,
- GtkTreePath *path,
- PsppSheetViewColumn *focus_column,
- gboolean start_editing);
-void pspp_sheet_view_set_cursor_on_cell (PsppSheetView *tree_view,
- GtkTreePath *path,
- PsppSheetViewColumn *focus_column,
- GtkCellRenderer *focus_cell,
- gboolean start_editing);
-void pspp_sheet_view_get_cursor (PsppSheetView *tree_view,
- GtkTreePath **path,
- PsppSheetViewColumn **focus_column);
-
-
-/* Layout information */
-GdkWindow *pspp_sheet_view_get_bin_window (PsppSheetView *tree_view);
-gboolean pspp_sheet_view_get_path_at_pos (PsppSheetView *tree_view,
- gint x,
- gint y,
- GtkTreePath **path,
- PsppSheetViewColumn **column,
- gint *cell_x,
- gint *cell_y);
-void pspp_sheet_view_get_cell_area (PsppSheetView *tree_view,
- GtkTreePath *path,
- PsppSheetViewColumn *column,
- GdkRectangle *rect);
-void pspp_sheet_view_get_background_area (PsppSheetView *tree_view,
- GtkTreePath *path,
- PsppSheetViewColumn *column,
- GdkRectangle *rect);
-void pspp_sheet_view_get_visible_rect (PsppSheetView *tree_view,
- GdkRectangle *visible_rect);
-
-#ifndef GTK_DISABLE_DEPRECATED
-void pspp_sheet_view_widget_to_tree_coords (PsppSheetView *tree_view,
- gint wx,
- gint wy,
- gint *tx,
- gint *ty);
-void pspp_sheet_view_tree_to_widget_coords (PsppSheetView *tree_view,
- gint tx,
- gint ty,
- gint *wx,
- gint *wy);
-#endif /* !GTK_DISABLE_DEPRECATED */
-gboolean pspp_sheet_view_get_visible_range (PsppSheetView *tree_view,
- GtkTreePath **start_path,
- GtkTreePath **end_path);
-
-/* Drag-and-Drop support */
-void pspp_sheet_view_enable_model_drag_source (PsppSheetView *tree_view,
- GdkModifierType start_button_mask,
- const GtkTargetEntry *targets,
- gint n_targets,
- GdkDragAction actions);
-void pspp_sheet_view_enable_model_drag_dest (PsppSheetView *tree_view,
- const GtkTargetEntry *targets,
- gint n_targets,
- GdkDragAction actions);
-void pspp_sheet_view_unset_rows_drag_source (PsppSheetView *tree_view);
-void pspp_sheet_view_unset_rows_drag_dest (PsppSheetView *tree_view);
-
-
-/* These are useful to implement your own custom stuff. */
-void pspp_sheet_view_set_drag_dest_row (PsppSheetView *tree_view,
- GtkTreePath *path,
- PsppSheetViewDropPosition pos);
-void pspp_sheet_view_get_drag_dest_row (PsppSheetView *tree_view,
- GtkTreePath **path,
- PsppSheetViewDropPosition *pos);
-gboolean pspp_sheet_view_get_dest_row_at_pos (PsppSheetView *tree_view,
- gint drag_x,
- gint drag_y,
- GtkTreePath **path,
- PsppSheetViewDropPosition *pos);
-
-/* Interactive search */
-void pspp_sheet_view_set_enable_search (PsppSheetView *tree_view,
- gboolean enable_search);
-gboolean pspp_sheet_view_get_enable_search (PsppSheetView *tree_view);
-gint pspp_sheet_view_get_search_column (PsppSheetView *tree_view);
-void pspp_sheet_view_set_search_column (PsppSheetView *tree_view,
- gint column);
-PsppSheetViewSearchEqualFunc pspp_sheet_view_get_search_equal_func (PsppSheetView *tree_view);
-void pspp_sheet_view_set_search_equal_func (PsppSheetView *tree_view,
- PsppSheetViewSearchEqualFunc search_equal_func,
- gpointer search_user_data,
- GDestroyNotify search_destroy);
-
-GtkEntry *pspp_sheet_view_get_search_entry (PsppSheetView *tree_view);
-void pspp_sheet_view_set_search_entry (PsppSheetView *tree_view,
- GtkEntry *entry);
-PsppSheetViewSearchPositionFunc pspp_sheet_view_get_search_position_func (PsppSheetView *tree_view);
-void pspp_sheet_view_set_search_position_func (PsppSheetView *tree_view,
- PsppSheetViewSearchPositionFunc func,
- gpointer data,
- GDestroyNotify destroy);
-
-/* Convert between the different coordinate systems */
-void pspp_sheet_view_convert_widget_to_tree_coords (PsppSheetView *tree_view,
- gint wx,
- gint wy,
- gint *tx,
- gint *ty);
-void pspp_sheet_view_convert_tree_to_widget_coords (PsppSheetView *tree_view,
- gint tx,
- gint ty,
- gint *wx,
- gint *wy);
-void pspp_sheet_view_convert_widget_to_bin_window_coords (PsppSheetView *tree_view,
- gint wx,
- gint wy,
- gint *bx,
- gint *by);
-void pspp_sheet_view_convert_bin_window_to_widget_coords (PsppSheetView *tree_view,
- gint bx,
- gint by,
- gint *wx,
- gint *wy);
-void pspp_sheet_view_convert_tree_to_bin_window_coords (PsppSheetView *tree_view,
- gint tx,
- gint ty,
- gint *bx,
- gint *by);
-void pspp_sheet_view_convert_bin_window_to_tree_coords (PsppSheetView *tree_view,
- gint bx,
- gint by,
- gint *tx,
- gint *ty);
-
-/* This function should really never be used. It is just for use by ATK.
- */
-typedef void (* PsppSheetDestroyCountFunc) (PsppSheetView *tree_view,
- GtkTreePath *path,
- gint children,
- gpointer user_data);
-void pspp_sheet_view_set_destroy_count_func (PsppSheetView *tree_view,
- PsppSheetDestroyCountFunc func,
- gpointer data,
- GDestroyNotify destroy);
-
-void pspp_sheet_view_set_hover_selection (PsppSheetView *tree_view,
- gboolean hover);
-gboolean pspp_sheet_view_get_hover_selection (PsppSheetView *tree_view);
-void pspp_sheet_view_set_rubber_banding (PsppSheetView *tree_view,
- gboolean enable);
-gboolean pspp_sheet_view_get_rubber_banding (PsppSheetView *tree_view);
-
-gboolean pspp_sheet_view_is_rubber_banding_active (PsppSheetView *tree_view);
-
-PsppSheetViewGridLines pspp_sheet_view_get_grid_lines (PsppSheetView *tree_view);
-void pspp_sheet_view_set_grid_lines (PsppSheetView *tree_view,
- PsppSheetViewGridLines grid_lines);
-
-PsppSheetViewSpecialCells pspp_sheet_view_get_special_cells (PsppSheetView *tree_view);
-void pspp_sheet_view_set_special_cells (PsppSheetView *tree_view,
- PsppSheetViewSpecialCells);
-
-int pspp_sheet_view_get_fixed_height (const PsppSheetView *);
-void pspp_sheet_view_set_fixed_height (PsppSheetView *,
- int fixed_height);
-
-/* Convenience functions for setting tooltips */
-void pspp_sheet_view_set_tooltip_row (PsppSheetView *tree_view,
- GtkTooltip *tooltip,
- GtkTreePath *path);
-void pspp_sheet_view_set_tooltip_cell (PsppSheetView *tree_view,
- GtkTooltip *tooltip,
- GtkTreePath *path,
- PsppSheetViewColumn *column,
- GtkCellRenderer *cell);
-gboolean pspp_sheet_view_get_tooltip_context(PsppSheetView *tree_view,
- gint *x,
- gint *y,
- gboolean keyboard_tip,
- GtkTreeModel **model,
- GtkTreePath **path,
- GtkTreeIter *iter);
-void pspp_sheet_view_set_tooltip_column (PsppSheetView *tree_view,
- gint column);
-gint pspp_sheet_view_get_tooltip_column (PsppSheetView *tree_view);
-
-void pspp_sheet_view_stop_editing (PsppSheetView *tree_view,
- gboolean cancel_editing);
-
-G_END_DECLS
-
-
-#endif /* __PSPP_SHEET_VIEW_H__ */
+++ /dev/null
-/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2011, 2012, 2014 Free Software Foundation, Inc.
-
- 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 <config.h>
-
-#include "pspp-widget-facade.h"
-
-#include <math.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-
-static void
-inset_rectangle (const GdkRectangle *src,
- const GtkBorder *inset,
- GdkRectangle *dst)
-{
- dst->x = src->x + inset->left;
- dst->y = src->y + inset->top;
- dst->width = MAX (1, src->width - inset->left - inset->right);
- dst->height = MAX (1, src->height - inset->top - inset->bottom);
-}
-
-static void
-thicken_border (gint x, gint y, GtkBorder *border)
-{
- border->left += x;
- border->right += x;
- border->top += y;
- border->bottom += y;
-}
-
-GtkStyle *
-facade_get_style (GtkWidget *base,
- GType type1,
- ...)
-{
- GString path, class_path;
- GType final_type;
- GtkStyle *style;
- va_list args;
- GType type;
-
- gtk_widget_path (base, NULL, &path.str, NULL);
- path.len = path.allocated_len = strlen (path.str);
-
- gtk_widget_class_path (base, NULL, &class_path.str, NULL);
- class_path.len = class_path.allocated_len = strlen (class_path.str);
-
- va_start (args, type1);
- for (type = final_type = type1; type != 0; type = va_arg (args, GType))
- {
- const gchar *type_name = g_type_name (type);
- g_string_append_printf (&path, ".%s", type_name);
- g_string_append_printf (&class_path, ".%s", type_name);
- final_type = type;
- }
- va_end (args);
-
- style = gtk_rc_get_style_by_paths (gtk_widget_get_settings (base),
- path.str, class_path.str, final_type);
-
- free (path.str);
- free (class_path.str);
-
- return style;
-}
-
-void
-facade_hbox_get_base_size_request (gint border_width,
- gint spacing,
- gint n_children,
- GtkRequisition *request)
-{
- request->width = border_width * 2;
- if (n_children > 1)
- request->width += spacing * (n_children - 1);
-
- request->height = border_width * 2;
-}
-
-void
-facade_hbox_add_child_size_request (gint hbox_border_width,
- const GtkRequisition *child_request,
- gint child_padding,
- GtkRequisition *request)
-{
- request->width += child_request->width + child_padding * 2;
- request->height = MAX (request->height,
- hbox_border_width * 2 + child_request->height);
-}
-
-void
-facade_arrow_get_size_request (gint xpad,
- gint ypad,
- GtkRequisition *request)
-{
-#define MIN_ARROW_SIZE 15
- request->width = MIN_ARROW_SIZE + xpad * 2;
- request->height = MIN_ARROW_SIZE + ypad * 2;
-}
-
-void
-facade_alignment_get_size_request (gint border_width,
- gint padding_left,
- gint padding_right,
- gint padding_top,
- gint padding_bottom,
- const GtkRequisition *child_request,
- GtkRequisition *request)
-{
- request->width = (border_width * 2 + padding_left + padding_right
- + child_request->width);
- request->height = (border_width * 2 + padding_top + padding_bottom
- + child_request->height);
-}
-
-void
-facade_label_get_size_request (gint xpad,
- gint ypad,
- GtkWidget *base,
- const char *text,
- GtkRequisition *request)
-{
- PangoLayout *layout;
-
- layout = facade_label_get_layout (base, text);
- facade_label_get_size_request_from_layout (xpad, ypad, layout, request);
- g_object_unref (layout);
-}
-
-void
-facade_label_get_size_request_from_layout (gint xpad,
- gint ypad,
- PangoLayout *layout,
- GtkRequisition *request)
-{
- PangoRectangle logical_rect;
-
- pango_layout_get_extents (layout, NULL, &logical_rect);
- request->width = xpad * 2 + PANGO_PIXELS (logical_rect.width);
- request->height = ypad * 2 + PANGO_PIXELS (logical_rect.height);
-}
-
-PangoLayout *
-facade_label_get_layout (GtkWidget *base,
- const char *text)
-{
- PangoAlignment alignment;
- PangoLayout *layout;
- gboolean rtl;
-
- rtl = gtk_widget_get_direction (base) == GTK_TEXT_DIR_RTL;
- alignment = rtl ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT;
-
- layout = gtk_widget_create_pango_layout (base, text);
- pango_layout_set_alignment (layout, alignment);
-
- return layout;
-}
-
-static void
-facade_button_get_inner_border (GtkStyle *button_style,
- GtkBorder *inner_border)
-{
- GtkBorder *tmp_border;
-
- gtk_style_get (button_style, GTK_TYPE_BUTTON,
- "inner-border", &tmp_border,
- NULL);
-
- if (tmp_border)
- {
- *inner_border = *tmp_border;
- gtk_border_free (tmp_border);
- }
- else
- {
- static const GtkBorder default_inner_border = { 1, 1, 1, 1 };
- *inner_border = default_inner_border;
- }
-}
-
-void
-facade_button_get_size_request (gint border_width,
- GtkWidget *base,
- GtkStyle *button_style,
- const GtkRequisition *child_request,
- GtkRequisition *request)
-{
- GtkBorder inner_border;
- gint common_width;
- gint focus_width;
- gint focus_pad;
-
- gtk_style_get (button_style, GTK_TYPE_BUTTON,
- "focus-line-width", &focus_width,
- "focus-padding", &focus_pad,
- NULL);
- facade_button_get_inner_border (button_style, &inner_border);
-
- common_width = 2 * (border_width + focus_width + focus_pad);
- request->width = (common_width
- + 2 * button_style->xthickness
- + inner_border.left + inner_border.right
- + child_request->width);
- request->height = (common_width
- + 2 * button_style->ythickness
- + inner_border.top + inner_border.bottom
- + child_request->height);
-}
-
-void
-facade_button_get_focus_inset (gint border_width,
- GtkWidget *base,
- GtkStyle *button_style,
- GtkBorder *focus_inset)
-{
- facade_button_get_inner_border (button_style, focus_inset);
- thicken_border (border_width + button_style->xthickness,
- border_width + button_style->ythickness,
- focus_inset);
-}
-
-static void
-facade_button_get_label_inset (gint border_width,
- GtkWidget *base,
- GtkStyle *button_style,
- GtkBorder *label_inset)
-{
- gint focus_width;
- gint focus_pad;
-
- facade_button_get_focus_inset (border_width, base, button_style,
- label_inset);
-
- gtk_style_get (button_style, GTK_TYPE_BUTTON,
- "focus-line-width", &focus_width,
- "focus-padding", &focus_pad,
- NULL);
- thicken_border (focus_width + focus_pad,
- focus_width + focus_pad,
- label_inset);
-}
-
-static void
-get_layout_location (GtkWidget *base,
- const GdkRectangle *label_area,
- PangoLayout *layout,
- gint xpad,
- gint ypad,
- gfloat xalign,
- gfloat yalign,
- gint *x,
- gint *y)
-{
- PangoRectangle logical;
- GtkRequisition req;
-
- if (gtk_widget_get_direction (base) == GTK_TEXT_DIR_RTL)
- xalign = 1.0 - xalign;
-
- pango_layout_get_pixel_extents (layout, NULL, &logical);
-
- facade_label_get_size_request_from_layout (xpad, ypad, layout, &req);
-
- *x = floor (label_area->x + xpad + xalign * (label_area->width - req.width));
-
- if (gtk_widget_get_direction (base) == GTK_TEXT_DIR_LTR)
- *x = MAX (*x, label_area->x + xpad);
- else
- *x = MIN (*x, label_area->x + label_area->width - xpad);
- *x -= logical.x;
-
- /* bgo#315462 - For single-line labels, *do* align the requisition with
- * respect to the allocation, even if we are under-allocated. For multi-line
- * labels, always show the top of the text when they are under-allocated.
- * The rationale is this:
- *
- * - Single-line labels appear in GtkButtons, and it is very easy to get them
- * to be smaller than their requisition. The button may clip the label,
- * but the label will still be able to show most of itself and the focus
- * rectangle. Also, it is fairly easy to read a single line of clipped
- * text.
- *
- * - Multi-line labels should not be clipped to showing "something in the
- * middle". You want to read the first line, at least, to get some
- * context.
- */
- if (pango_layout_get_line_count (layout) == 1)
- *y = floor (label_area->y + ypad
- + (label_area->height - req.height) * yalign);
- else
- *y = floor (label_area->y + ypad
- + MAX (((label_area->height - req.height) * yalign),
- 0));
-}
-
-void
-facade_button_render (GtkWidget *base,
- cairo_t *cr,
- const GdkRectangle *button_area,
- gint border_width,
- GtkStyle *button_style,
- GtkStateType state_type,
-
- GtkStyle *label_style,
- const gchar *label,
- gint xpad,
- gint ypad,
- gfloat xalign,
- gfloat yalign)
-{
- GdkRectangle label_area;
- PangoLayout *layout;
- GtkBorder inset;
- gint x, y;
-
- /* Paint the button. */
- gtk_paint_box (button_style, cr,
- state_type,
- GTK_SHADOW_OUT, base, "button",
- button_area->x + border_width,
- button_area->y + border_width,
- button_area->width - border_width * 2,
- button_area->height - border_width * 2);
-
- /* Figure out where the label should go. */
- facade_button_get_label_inset (border_width, base, button_style, &inset);
- inset_rectangle (button_area, &inset, &label_area);
-
- /* Paint the label. */
- layout = facade_label_get_layout (base, label);
- get_layout_location (base, &label_area, layout, xpad, ypad, xalign, yalign,
- &x, &y);
-
- gtk_paint_layout (label_style, cr, state_type, FALSE,
- base, "label", x, y, layout);
-
- g_object_unref (layout);
-}
-
+++ /dev/null
-/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2011, 2012 Free Software Foundation, Inc.
-
- 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/>. */
-
-#ifndef FACADE_WIDGET_FACADE_H
-#define FACADE_WIDGET_FACADE_H 1
-
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-GtkStyle *facade_get_style (GtkWidget *base, GType, ...);
-
-void facade_hbox_get_base_size_request (gint border_width,
- gint spacing,
- gint n_children,
- GtkRequisition *);
-void facade_hbox_add_child_size_request (gint hbox_border_width,
- const GtkRequisition *child_request,
- gint child_padding,
- GtkRequisition *);
-
-void facade_arrow_get_size_request (gint xpad,
- gint ypad,
- GtkRequisition *);
-
-
-void facade_alignment_get_size_request (gint border_width,
- gint padding_left,
- gint padding_right,
- gint padding_top,
- gint padding_bottom,
- const GtkRequisition *child_request,
- GtkRequisition *);
-
-void facade_label_get_size_request (gint xpad,
- gint ypad,
- GtkWidget *base,
- const char *text,
- GtkRequisition *);
-void facade_label_get_size_request_from_layout (gint xpad,
- gint ypad,
- PangoLayout *,
- GtkRequisition *);
-PangoLayout *facade_label_get_layout (GtkWidget *base,
- const char *text);
-
-void facade_button_get_size_request (gint border_width,
- GtkWidget *base,
- GtkStyle *button_style,
- const GtkRequisition *child_request,
- GtkRequisition *);
-void facade_button_render (GtkWidget *base,
- cairo_t *cr,
- const GdkRectangle *button_area,
- gint border_width,
- GtkStyle *button_style,
- GtkStateType state_type,
-
- GtkStyle *label_style,
- const gchar *label,
- gint xpad,
- gint ypad,
- gfloat xalign,
- gfloat yalign);
-void facade_button_get_focus_inset (gint border_width,
- GtkWidget *base,
- GtkStyle *button_style,
- GtkBorder *focus_inset);
-
-G_END_DECLS
-
-#endif /* FACADE_WIDGET_FACADE_H */
+++ /dev/null
-/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2011, 2012, 2016 Free Software Foundation, Inc.
-
- 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 <config.h>
-
-#include "ui/gui/psppire-button-editable.h"
-
-#include <gettext.h>
-#define _(msgid) gettext (msgid)
-#define N_(msgid) msgid
-#define P_(STRING) STRING
-
-/* GtkCellEditable interface. */
-static void gtk_cell_editable_interface_init (GtkCellEditableIface *iface);
-static void button_editable_editing_done (GtkCellEditable *cell_editable);
-static void button_editable_remove_widget (GtkCellEditable *cell_editable);
-static void button_editable_start_editing (GtkCellEditable *cell_editable,
- GdkEvent *event);
-
-G_DEFINE_TYPE_EXTENDED (PsppireButtonEditable,
- psppire_button_editable,
- GTK_TYPE_BUTTON,
- 0,
- G_IMPLEMENT_INTERFACE (
- GTK_TYPE_CELL_EDITABLE,
- gtk_cell_editable_interface_init));
-
-enum
- {
- PROP_0,
- PROP_PATH,
- PROP_EDITING_CANCELED
- };
-
-static void
-psppire_button_editable_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- PsppireButtonEditable *obj = PSPPIRE_BUTTON_EDITABLE (object);
-
- switch (prop_id)
- {
- case PROP_PATH:
- g_free (obj->path);
- obj->path = g_value_dup_string (value);
- break;
-
- case PROP_EDITING_CANCELED:
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-psppire_button_editable_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- PsppireButtonEditable *obj = PSPPIRE_BUTTON_EDITABLE (object);
-
- switch (prop_id)
- {
- case PROP_PATH:
- g_value_set_string (value, obj->path);
- break;
-
- case PROP_EDITING_CANCELED:
- g_value_set_boolean (value, FALSE);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-psppire_button_editable_finalize (GObject *gobject)
-{
- PsppireButtonEditable *obj = PSPPIRE_BUTTON_EDITABLE (gobject);
-
- g_free (obj->path);
-
- G_OBJECT_CLASS (psppire_button_editable_parent_class)->finalize (gobject);
-}
-
-static gboolean
-psppire_button_editable_button_release (GtkWidget *widget,
- GdkEventButton *event)
-{
- if (event->button == 1)
- {
- g_signal_emit_by_name (widget, "released", event, NULL);
- }
-
- return TRUE;
-}
-
-static void
-psppire_button_editable_class_init (PsppireButtonEditableClass *class)
-{
- GObjectClass *gobject_class;
- GtkWidgetClass *widget_class;
-
- gobject_class = G_OBJECT_CLASS (class);
- widget_class = GTK_WIDGET_CLASS (class);
-
- gobject_class->set_property = psppire_button_editable_set_property;
- gobject_class->get_property = psppire_button_editable_get_property;
- gobject_class->finalize = psppire_button_editable_finalize;
-
- widget_class->button_release_event = psppire_button_editable_button_release;
-
- g_object_class_install_property (gobject_class,
- PROP_PATH,
- g_param_spec_string ("path",
- P_("TreeView path"),
- P_("The path to the row in the GtkTreeView, as a string"),
- "",
- G_PARAM_READWRITE));
-
- g_object_class_override_property (gobject_class,
- PROP_EDITING_CANCELED,
- "editing-canceled");
-}
-
-static void
-psppire_button_editable_init (PsppireButtonEditable *obj)
-{
- obj->path = g_strdup ("");
-}
-
-PsppireButtonEditable *
-psppire_button_editable_new (void)
-{
- return PSPPIRE_BUTTON_EDITABLE (g_object_new (PSPPIRE_TYPE_BUTTON_EDITABLE, NULL));
-}
-
-\f
-/* GtkCellEditable interface. */
-
-static void
-gtk_cell_editable_interface_init (GtkCellEditableIface *iface)
-{
- g_return_if_fail (iface != NULL);
-
- iface->editing_done = button_editable_editing_done;
- iface->remove_widget = button_editable_remove_widget;
- iface->start_editing = button_editable_start_editing;
-}
-
-static void
-button_editable_editing_done (GtkCellEditable *cell_editable)
-{
-}
-
-static void
-button_editable_remove_widget (GtkCellEditable *cell_editable)
-{
-}
-
-static void
-button_editable_start_editing (GtkCellEditable *cell_editable,
- GdkEvent *event)
-{
-}
+++ /dev/null
-/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2011, 2012 Free Software Foundation, Inc.
-
- 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/>. */
-
-#ifndef PSPPIRE_BUTTON_EDITABLE_H
-#define PSPPIRE_BUTTON_EDITABLE_H 1
-
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-#define PSPPIRE_TYPE_BUTTON_EDITABLE (psppire_button_editable_get_type())
-#define PSPPIRE_BUTTON_EDITABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),PSPPIRE_TYPE_BUTTON_EDITABLE,PsppireButtonEditable))
-#define PSPPIRE_BUTTON_EDITABLE_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class),PSPPIRE_TYPE_BUTTON_EDITABLE,PsppireButtonEditableClass))
-#define PSPPIRE_IS_BUTTON_EDITABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),PSPPIRE_TYPE_BUTTON_EDITABLE))
-#define PSPPIRE_IS_BUTTON_EDITABLE_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class),PSPPIRE_TYPE_BUTTON_EDITABLE))
-#define PSPPIRE_BUTTON_EDITABLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),PSPPIRE_TYPE_BUTTON_EDITABLE,PsppireButtonEditableClass))
-
-typedef struct _PsppireButtonEditable PsppireButtonEditable;
-typedef struct _PsppireButtonEditableClass PsppireButtonEditableClass;
-
-struct _PsppireButtonEditable {
- GtkButton parent;
- gchar *path;
-};
-
-struct _PsppireButtonEditableClass {
- GtkButtonClass parent_class;
-};
-
-GType psppire_button_editable_get_type (void) G_GNUC_CONST;
-PsppireButtonEditable* psppire_button_editable_new (void);
-
-G_END_DECLS
-
-#endif /* PSPPIRE_BUTTON_EDITABLE_H */
+++ /dev/null
-/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2011, 2012 Free Software Foundation, Inc.
-
- 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 <config.h>
-
-#include "ui/gui/psppire-cell-renderer-button.h"
-
-#include <math.h>
-#include <string.h>
-
-#include "ui/gui/psppire-button-editable.h"
-#include "ui/gui/pspp-widget-facade.h"
-
-#include "gl/configmake.h"
-#include "gl/relocatable.h"
-
-#define P_(msgid) (msgid)
-
-static void psppire_cell_renderer_button_dispose (GObject *);
-static void psppire_cell_renderer_button_finalize (GObject *);
-
-static void update_style_cache (PsppireCellRendererButton *button,
- GtkWidget *widget);
-
-static void psppire_cell_renderer_button_load_gtkrc (void);
-
-
-G_DEFINE_TYPE_EXTENDED (PsppireCellRendererButton,
- psppire_cell_renderer_button,
- GTK_TYPE_CELL_RENDERER,
- 0,
- psppire_cell_renderer_button_load_gtkrc ());
-
-static void
-psppire_cell_renderer_button_load_gtkrc (void)
-{
- const char *gtkrc_file;
-
- gtkrc_file = relocate (PKGDATADIR "/psppire.gtkrc");
- gtk_rc_add_default_file (gtkrc_file);
- gtk_rc_parse (gtkrc_file);
-}
-
-enum
- {
- PROP_0,
- PROP_EDITABLE,
- PROP_LABEL,
- PROP_SLASH
- };
-
-static void
-psppire_cell_renderer_button_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- PsppireCellRendererButton *obj = PSPPIRE_CELL_RENDERER_BUTTON (object);
- switch (prop_id)
- {
- case PROP_EDITABLE:
- obj->editable = g_value_get_boolean (value);
- if (obj->editable)
- g_object_set (obj, "mode", GTK_CELL_RENDERER_MODE_EDITABLE, NULL);
- else
- g_object_set (obj, "mode", GTK_CELL_RENDERER_MODE_INERT, NULL);
- break;
-
- case PROP_LABEL:
- g_free (obj->label);
- obj->label = g_value_dup_string (value);
- break;
-
- case PROP_SLASH:
- psppire_cell_renderer_button_set_slash (obj,
- g_value_get_boolean (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-psppire_cell_renderer_button_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- PsppireCellRendererButton *obj = PSPPIRE_CELL_RENDERER_BUTTON (object);
-
- switch (prop_id)
- {
- case PROP_EDITABLE:
- g_value_set_boolean (value, obj->editable);
- break;
-
- case PROP_LABEL:
- g_value_set_string (value, obj->label);
- break;
-
- case PROP_SLASH:
- g_value_set_boolean (value,
- psppire_cell_renderer_button_get_slash (obj));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-on_style_set (GtkWidget *base,
- GtkStyle *previous_style,
- PsppireCellRendererButton *button)
-{
- update_style_cache (button, NULL);
-}
-
-static void
-update_style_cache (PsppireCellRendererButton *button,
- GtkWidget *widget)
-{
- if (button->base == widget)
- return;
-
- /* Clear old cache. */
- if (button->button_style)
- {
- g_object_unref (button->button_style);
- button->button_style = NULL;
- }
- if (button->label_style)
- {
- g_object_unref (button->label_style);
- button->label_style = NULL;
- }
- if (button->base != NULL)
- {
- if (button->style_set_handler)
- {
- g_signal_handler_disconnect (button->base,
- button->style_set_handler);
- button->style_set_handler = 0;
- }
- g_object_unref (button->base);
- button->base = NULL;
- }
-
- /* Populate cache. */
- if (widget)
- {
- button->button_style = facade_get_style (widget, GTK_TYPE_BUTTON, 0);
- button->label_style = facade_get_style (widget, GTK_TYPE_BUTTON,
- GTK_TYPE_LABEL, 0);
- button->base = widget;
- button->style_set_handler = g_signal_connect (widget, "style-set",
- G_CALLBACK (on_style_set),
- button);
- g_object_ref (widget);
- g_object_ref (button->button_style);
- g_object_ref (button->label_style);
- }
-}
-
-static void
-psppire_cell_renderer_button_render (GtkCellRenderer *cell,
- cairo_t *cr,
- GtkWidget *widget,
- const GdkRectangle *background_area,
- const GdkRectangle *cell_area,
- GtkCellRendererState flags)
-{
- GtkStateType state_type;
- PsppireCellRendererButton *button = PSPPIRE_CELL_RENDERER_BUTTON (cell);
- gfloat xalign, yalign;
-
- if (!button->editable || ! gtk_cell_renderer_get_sensitive (cell))
- state_type = GTK_STATE_INSENSITIVE;
- else if (flags & GTK_CELL_RENDERER_SELECTED)
- {
- if (gtk_widget_has_focus (widget))
- state_type = GTK_STATE_SELECTED;
- else
- state_type = GTK_STATE_ACTIVE;
- }
- else if (flags & GTK_CELL_RENDERER_PRELIT)
- state_type = GTK_STATE_PRELIGHT;
- else
- {
- if (gtk_widget_get_state_flags (widget) == GTK_STATE_FLAG_INSENSITIVE)
- state_type = GTK_STATE_INSENSITIVE;
- else
- state_type = GTK_STATE_NORMAL;
- }
-
- gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
-
-
- update_style_cache (button, widget);
-
- facade_button_render (widget, cr,
- cell_area, button->border_width, button->button_style,
- state_type,
- button->label_style, button->label, button->xpad,
- button->ypad, xalign, yalign);
-
- if (button->slash)
- {
- cairo_set_line_width (cr, 1.0);
- cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
- cairo_move_to (cr,
- cell_area->x,
- cell_area->y + cell_area->height);
-
- cairo_line_to (cr,
- cell_area->x + cell_area->width,
- cell_area->y);
- cairo_stroke (cr);
- }
-}
-
-static void
-psppire_cell_renderer_button_get_size (GtkCellRenderer *cell,
- GtkWidget *widget,
- const GdkRectangle *cell_area,
- gint *x_offset,
- gint *y_offset,
- gint *width,
- gint *height)
-{
- PsppireCellRendererButton *button = PSPPIRE_CELL_RENDERER_BUTTON (cell);
-
- update_style_cache (button, widget);
- if (cell_area != NULL)
- {
- /* The caller is really asking for the placement of the focus rectangle.
- The focus rectangle should surround the whole label area, so calculate
- that area. */
- GtkBorder inset;
-
- facade_button_get_focus_inset (button->border_width, widget,
- button->button_style, &inset);
-
- if (x_offset)
- *x_offset = inset.left;
- if (y_offset)
- *y_offset = inset.top;
- if (width)
- *width = MAX (1, cell_area->width - inset.left - inset.right);
- if (height)
- *height = MAX (1, cell_area->height - inset.top - inset.bottom);
- }
- else
- {
- /* The caller is asking for the preferred size of the cell. */
- GtkRequisition label_req;
- GtkRequisition request;
-
- facade_label_get_size_request (button->xpad, button->ypad,
- widget, button->label, &label_req);
- facade_button_get_size_request (button->border_width, widget,
- button->button_style, &label_req,
- &request);
-
- if (x_offset)
- *x_offset = 0;
- if (y_offset)
- *y_offset = 0;
- if (width)
- *width = request.width;
- if (height)
- *height = request.height;
- }
-}
-
-static void
-psppire_cell_renderer_button_clicked (GtkButton *button,
- gpointer data)
-{
- PsppireCellRendererButton *cell_button = data;
- gchar *path;
-
- g_object_get (button, "path", &path, NULL);
- g_signal_emit_by_name (cell_button, "clicked", path);
- g_free (path);
-}
-
-#define IDLE_ID_STRING "psppire-cell-renderer-button-idle-id"
-
-static gboolean
-psppire_cell_renderer_button_initial_click (gpointer data)
-{
- GtkButton *button = data;
-
- g_object_steal_data (G_OBJECT (button), IDLE_ID_STRING);
- gtk_button_clicked (button);
- return FALSE;
-}
-
-static void
-psppire_cell_renderer_button_on_destroy (GObject *object, gpointer user_data)
-{
- guint idle_id;
-
- idle_id = GPOINTER_TO_INT (g_object_steal_data (object, IDLE_ID_STRING));
- if (idle_id != 0)
- g_source_remove (idle_id);
-}
-
-static void
-psppire_cell_renderer_button_double_click (GtkButton *button,
- PsppireCellRendererButton *cell_button)
-{
- gchar *path;
-
- if (g_object_get_data (G_OBJECT (button), IDLE_ID_STRING))
- psppire_cell_renderer_button_initial_click (button);
-
- g_object_get (button, "path", &path, NULL);
- g_signal_emit_by_name (cell_button, "double-clicked", path);
- g_free (path);
-}
-
-static gboolean
-psppire_cell_renderer_button_press_event (GtkButton *button,
- GdkEventButton *event,
- gpointer data)
-{
- PsppireCellRendererButton *cell_button = data;
-
- if (event->button == 3)
- {
- /* Allow right-click events to propagate upward in the widget hierarchy.
- Otherwise right-click menus, that trigger on a button-press-event on
- the containing PsppSheetView, will pop up if the button is rendered as
- a facade but not if the button widget exists.
-
- We have to translate the event's data by hand to be relative to the
- parent window, because the normal GObject signal propagation mechanism
- won't do it for us. (This might be a hint that we're doing this
- wrong.) */
- gint x, y;
-
- gdk_window_get_position (event->window, &x, &y);
- event->x += x;
- event->y += y;
- g_signal_stop_emission_by_name (button, "button-press-event");
- return FALSE;
- }
-
- if (cell_button->click_time != 0)
- {
- GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (button));
- GtkSettings *settings = gtk_settings_get_for_screen (screen);
- gint double_click_distance;
- gint double_click_time;
-
- g_object_get (settings,
- "gtk-double-click-time", &double_click_time,
- "gtk-double-click-distance", &double_click_distance,
- NULL);
-
- if (event->type == GDK_BUTTON_PRESS
- && event->button == 1
- && event->time <= cell_button->click_time + double_click_time
- && ABS (event->x_root - cell_button->click_x) <= double_click_distance
- && ABS (event->y_root - cell_button->click_y) <= double_click_distance)
- {
- psppire_cell_renderer_button_double_click (button, cell_button);
- return TRUE;
- }
-
- cell_button->click_time = 0;
- }
-
- if (event->type == GDK_2BUTTON_PRESS)
- {
- psppire_cell_renderer_button_double_click (button, cell_button);
- return TRUE;
- }
-
- return FALSE;
-}
-
-static GtkCellEditable *
-psppire_cell_renderer_button_start_editing (GtkCellRenderer *cell,
- GdkEvent *event,
- GtkWidget *widget,
- const gchar *path,
- const GdkRectangle *background_area,
- const GdkRectangle *cell_area,
- GtkCellRendererState flags)
-{
- PsppireCellRendererButton *cell_button = PSPPIRE_CELL_RENDERER_BUTTON (cell);
- gfloat xalign, yalign;
-
- gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
- cell_button->button = g_object_new (PSPPIRE_TYPE_BUTTON_EDITABLE,
- "label", cell_button->label,
- "xalign", xalign,
- "yalign", yalign,
- "path", path,
- NULL);
-
- g_signal_connect (G_OBJECT (cell_button->button), "clicked",
- G_CALLBACK (psppire_cell_renderer_button_clicked),
- cell);
- g_signal_connect (G_OBJECT (cell_button->button), "button-press-event",
- G_CALLBACK (psppire_cell_renderer_button_press_event),
- cell);
-
- gtk_widget_show (cell_button->button);
-
- if (event != NULL && event->any.type == GDK_BUTTON_RELEASE)
- {
- guint idle_id;
-
- cell_button->click_time = event->button.time;
- cell_button->click_x = event->button.x_root;
- cell_button->click_y = event->button.y_root;
- idle_id = g_idle_add (psppire_cell_renderer_button_initial_click,
- cell_button->button);
- g_object_set_data (G_OBJECT (cell_button->button), IDLE_ID_STRING,
- GINT_TO_POINTER (idle_id));
- g_signal_connect (G_OBJECT (cell_button->button), "destroy",
- G_CALLBACK (psppire_cell_renderer_button_on_destroy),
- NULL);
- }
- else
- {
- cell_button->click_time = 0;
- cell_button->click_x = 0;
- cell_button->click_y = 0;
- }
-
- return GTK_CELL_EDITABLE (cell_button->button);
-}
-
-static void
-psppire_cell_renderer_button_class_init (PsppireCellRendererButtonClass *class)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (class);
- GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class);
-
- gobject_class->set_property = psppire_cell_renderer_button_set_property;
- gobject_class->get_property = psppire_cell_renderer_button_get_property;
- gobject_class->finalize = psppire_cell_renderer_button_finalize;
- gobject_class->dispose = psppire_cell_renderer_button_dispose;
-
- cell_class->get_size = psppire_cell_renderer_button_get_size;
- cell_class->render = psppire_cell_renderer_button_render;
- cell_class->start_editing = psppire_cell_renderer_button_start_editing;
-
- g_signal_new ("clicked",
- G_TYPE_FROM_CLASS (gobject_class),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE,
- 1, G_TYPE_STRING);
-
- g_signal_new ("double-clicked",
- G_TYPE_FROM_CLASS (gobject_class),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE,
- 1, G_TYPE_STRING);
-
- g_object_class_install_property (gobject_class,
- PROP_EDITABLE,
- g_param_spec_boolean ("editable",
- P_("Editable"),
- P_("Whether the button may be clicked."),
- FALSE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (gobject_class,
- PROP_LABEL,
- g_param_spec_string ("label",
- P_("Label"),
- P_("Text to appear in button."),
- "",
- G_PARAM_READWRITE));
-
- g_object_class_install_property (gobject_class,
- PROP_SLASH,
- g_param_spec_boolean ("slash",
- P_("Diagonal slash"),
- P_("Whether to draw a diagonal slash across the button."),
- FALSE,
- G_PARAM_READWRITE));
-
-}
-
-static void
-psppire_cell_renderer_button_init (PsppireCellRendererButton *obj)
-{
- obj->editable = FALSE;
- obj->label = g_strdup ("");
- obj->border_width = 0;
- obj->xpad = 0;
- obj->ypad = 0;
-
- obj->slash = FALSE;
-
- obj->button = NULL;
-
- obj->button_style = NULL;
- obj->label_style = NULL;
- obj->base = NULL;
- obj->style_set_handler = 0;
- obj->dispose_has_run = FALSE;
-}
-
-static void
-psppire_cell_renderer_button_finalize (GObject *obj)
-{
- PsppireCellRendererButton *button = PSPPIRE_CELL_RENDERER_BUTTON (obj);
-
- g_free (button->label);
-}
-
-static void
-psppire_cell_renderer_button_dispose (GObject *obj)
-{
- PsppireCellRendererButton *button = PSPPIRE_CELL_RENDERER_BUTTON (obj);
-
- if (button->dispose_has_run)
- return;
-
- button->dispose_has_run = TRUE;
-
- /* When called with NULL, as we are doing here, update_style_cache
- does nothing more than to drop references */
- update_style_cache (button, NULL);
-
- G_OBJECT_CLASS (psppire_cell_renderer_button_parent_class)->dispose (obj);
-}
-
-GtkCellRenderer *
-psppire_cell_renderer_button_new (void)
-{
- return GTK_CELL_RENDERER (g_object_new (PSPPIRE_TYPE_CELL_RENDERER_BUTTON, NULL));
-}
-
-void
-psppire_cell_renderer_button_set_slash (PsppireCellRendererButton *button,
- gboolean slash)
-{
- g_return_if_fail (button != NULL);
- button->slash = slash;
-}
-
-gboolean
-psppire_cell_renderer_button_get_slash (const PsppireCellRendererButton *button)
-{
- g_return_val_if_fail (button != NULL, FALSE);
- return button->slash;
-}
+++ /dev/null
-/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2011, 2012 Free Software Foundation, Inc.
-
- 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/>. */
-
-#ifndef PSPPIRE_CELL_RENDERER_BUTTON_H
-#define PSPPIRE_CELL_RENDERER_BUTTON_H 1
-
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-#define PSPPIRE_TYPE_CELL_RENDERER_BUTTON (psppire_cell_renderer_button_get_type())
-#define PSPPIRE_CELL_RENDERER_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),PSPPIRE_TYPE_CELL_RENDERER_BUTTON,PsppireCellRendererButton))
-#define PSPPIRE_CELL_RENDERER_BUTTON_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class),PSPPIRE_TYPE_CELL_RENDERER_BUTTON,PsppireCellRendererButtonClass))
-#define PSPPIRE_IS_CELL_RENDERER_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),PSPPIRE_TYPE_CELL_RENDERER_BUTTON))
-#define PSPPIRE_IS_CELL_RENDERER_BUTTON_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class),PSPPIRE_TYPE_CELL_RENDERER_BUTTON))
-#define PSPPIRE_CELL_RENDERER_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),PSPPIRE_TYPE_CELL_RENDERER_BUTTON,PsppireCellRendererButtonClass))
-
-typedef struct _PsppireCellRendererButton PsppireCellRendererButton;
-typedef struct _PsppireCellRendererButtonClass PsppireCellRendererButtonClass;
-
-struct _PsppireCellRendererButton
-{
- GtkCellRenderer parent;
-
- gboolean editable;
- gchar *label;
- gint border_width;
- gint xpad;
- gint ypad;
-
- gboolean slash;
-
- GtkWidget *button;
- guint32 click_time;
- gdouble click_x;
- gdouble click_y;
-
- /* Style caching. */
- GtkStyle *button_style;
- GtkStyle *label_style;
- GtkWidget *base;
- gulong style_set_handler;
- gboolean dispose_has_run;
-};
-
-struct _PsppireCellRendererButtonClass {
- GtkCellRendererClass parent_class;
-};
-
-GType psppire_cell_renderer_button_get_type (void) G_GNUC_CONST;
-GtkCellRenderer* psppire_cell_renderer_button_new (void);
-
-void psppire_cell_renderer_button_set_slash (PsppireCellRendererButton *,
- gboolean slash);
-gboolean psppire_cell_renderer_button_get_slash (const PsppireCellRendererButton *);
-
-G_END_DECLS
-
-#endif /* PSPPIRE_CELL_RENDERER_BUTTON_H */
/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009, 2010, 2011, 2012, 2016 Free Software Foundation, Inc.
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
#include "libpspp/range-set.h"
#include "libpspp/str.h"
#include "ui/gui/helper.h"
-#include "ui/gui/pspp-sheet-selection.h"
-#include "ui/gui/psppire-data-sheet.h"
#include "ui/gui/psppire-data-store.h"
#include "ui/gui/psppire-value-entry.h"
-#include "ui/gui/psppire-var-sheet.h"
#include "ui/gui/psppire-conf.h"
+#include "ui/gui/psppire-var-sheet-header.h"
+
+#include "value-variant.h"
+
+
+#include "ui/gui/efficient-sheet/jmd-sheet.h"
+#include "ui/gui/efficient-sheet/jmd-sheet-body.h"
#include <gettext.h>
#define _(msgid) gettext (msgid)
-#define FOR_EACH_DATA_SHEET(DATA_SHEET, IDX, DATA_EDITOR) \
- for ((IDX) = 0; \
- (IDX) < 4 \
- && ((DATA_SHEET) = PSPPIRE_DATA_SHEET ( \
- (DATA_EDITOR)->data_sheets[IDX])) != NULL; \
- (IDX)++)
+
+static GtkCellRenderer *
+create_spin_renderer (GType type)
+{
+ GtkCellRenderer *r = gtk_cell_renderer_spin_new ();
+
+ GtkAdjustment *adj = gtk_adjustment_new (0,
+ 0, G_MAXDOUBLE,
+ 1, 1,
+ 0);
+ g_object_set (r,
+ "adjustment", adj,
+ NULL);
+
+ return r;
+}
+
+static GtkCellRenderer *
+create_combo_renderer (GType type)
+{
+ GtkListStore *list_store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
+
+ GEnumClass *ec = g_type_class_ref (type);
+
+ const GEnumValue *ev ;
+ for (ev = ec->values; ev->value_name; ++ev)
+ {
+ GtkTreeIter iter;
+
+ gtk_list_store_append (list_store, &iter);
+
+ gtk_list_store_set (list_store, &iter,
+ 0, ev->value,
+ 1, gettext (ev->value_nick),
+ -1);
+ }
+
+ GtkCellRenderer *r = gtk_cell_renderer_combo_new ();
+
+ g_object_set (r,
+ "model", list_store,
+ "text-column", 1,
+ "has-entry", TRUE,
+ NULL);
+
+ return r;
+}
+
+GtkCellRenderer *xx ;
+GtkCellRenderer *column_width_renderer ;
+GtkCellRenderer *measure_renderer ;
+GtkCellRenderer *alignment_renderer ;
+
+
+
+static GtkCellRenderer *
+select_renderer_func (gint col, gint row, GType type)
+{
+ if (!xx)
+ xx = create_spin_renderer (type);
+
+ if (col == DICT_TVM_COL_ROLE && !column_width_renderer)
+ column_width_renderer = create_combo_renderer (type);
+
+ if (col == DICT_TVM_COL_MEASURE && !measure_renderer)
+ measure_renderer = create_combo_renderer (type);
+
+ if (col == DICT_TVM_COL_ALIGNMENT && !alignment_renderer)
+ alignment_renderer = create_combo_renderer (type);
+
+ switch (col)
+ {
+ case DICT_TVM_COL_WIDTH:
+ case DICT_TVM_COL_DECIMAL:
+ case DICT_TVM_COL_COLUMNS:
+ return xx;
+
+ case DICT_TVM_COL_ALIGNMENT:
+ return alignment_renderer;
+
+ case DICT_TVM_COL_MEASURE:
+ return measure_renderer;
+
+ case DICT_TVM_COL_ROLE:
+ return column_width_renderer;
+ }
+
+ return NULL;
+}
+
static void psppire_data_editor_class_init (PsppireDataEditorClass *klass);
static void psppire_data_editor_init (PsppireDataEditor *de);
static void
psppire_data_editor_refresh_model (PsppireDataEditor *de)
{
- PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (de->var_sheet);
- PsppireDataSheet *data_sheet;
- int i;
+}
+
+static void
+change_var_property (PsppireDict *dict, gint col, gint row, GValue *value)
+{
+ /* Return the IDXth variable */
+ struct variable *var = psppire_dict_get_variable (dict, row);
- FOR_EACH_DATA_SHEET (data_sheet, i, de)
- psppire_data_sheet_set_data_store (data_sheet, de->data_store);
- psppire_var_sheet_set_dictionary (var_sheet, de->dict);
+ switch (col)
+ {
+ case DICT_TVM_COL_NAME:
+ dict_rename_var (dict->dict, var, g_value_get_string (value));
+ break;
+ case DICT_TVM_COL_LABEL:
+ var_set_label (var, g_value_get_string (value));
+ break;
+ case DICT_TVM_COL_COLUMNS:
+ var_set_display_width (var, g_value_get_int (value));
+ break;
+ case DICT_TVM_COL_MEASURE:
+ var_set_measure (var, g_value_get_enum (value));
+ break;
+ case DICT_TVM_COL_ALIGNMENT:
+ var_set_alignment (var, g_value_get_enum (value));
+ break;
+ case DICT_TVM_COL_ROLE:
+ var_set_role (var, g_value_get_enum (value));
+ break;
+ default:
+ g_message ("Changing col %d of var sheet not yet supported", col);
+ break;
+ }
+}
+
+static void
+change_data_value (PsppireDataStore *store, gint col, gint row, GValue *value)
+{
+ const struct variable *var = psppire_dict_get_variable (store->dict, col);
+
+ if (NULL == var)
+ return;
+
+ union value v;
+
+ GVariant *vrnt = g_value_get_variant (value);
+
+ value_variant_get (&v, vrnt);
+
+ psppire_data_store_set_value (store, row, var, &v);
+
+ value_destroy_from_variant (&v, vrnt);
}
static void
GParamSpec *pspec)
{
PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (object);
- PsppireDataSheet *data_sheet;
- int i;
switch (prop_id)
{
de->data_store = g_value_get_pointer (value);
g_object_ref (de->data_store);
+ g_print ("NEW STORE\n");
+
+ g_object_set (de->data_sheet, "data-model", de->data_store, NULL);
psppire_data_editor_refresh_model (de);
+ g_signal_connect_swapped (de->data_sheet, "value-changed",
+ G_CALLBACK (change_data_value), de->data_store);
+
g_signal_connect_swapped (de->data_store, "case-changed",
G_CALLBACK (refresh_entry), de);
de->dict = g_value_get_pointer (value);
g_object_ref (de->dict);
- psppire_var_sheet_set_dictionary (PSPPIRE_VAR_SHEET (de->var_sheet),
- de->dict);
+ g_object_set (de->data_sheet, "hmodel", de->dict, NULL);
+ g_object_set (de->var_sheet, "data-model", de->dict, NULL);
+ g_signal_connect_swapped (de->var_sheet, "value-changed",
+ G_CALLBACK (change_var_property), de->dict);
+
break;
case PROP_VALUE_LABELS:
- FOR_EACH_DATA_SHEET (data_sheet, i, de)
- psppire_data_sheet_set_value_labels (data_sheet,
- g_value_get_boolean (value));
break;
default:
g_value_set_pointer (value, de->dict);
break;
case PROP_VALUE_LABELS:
- g_value_set_boolean (value,
- psppire_data_sheet_get_value_labels (
- PSPPIRE_DATA_SHEET (de->data_sheets[0])));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
-static gboolean
-on_data_sheet_var_double_clicked (PsppireDataSheet *data_sheet,
- gint dict_index,
- PsppireDataEditor *de)
+
+static void
+on_var_sheet_var_double_clicked (void *var_sheet, gint dict_index,
+ PsppireDataEditor *de)
{
gtk_notebook_set_current_page (GTK_NOTEBOOK (de),
- PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
-
- psppire_var_sheet_goto_variable (PSPPIRE_VAR_SHEET (de->var_sheet),
- dict_index);
+ PSPPIRE_DATA_EDITOR_DATA_VIEW);
- return TRUE;
+ jmd_sheet_scroll_to (JMD_SHEET (de->data_sheet), dict_index, -1);
}
-static gboolean
-on_var_sheet_var_double_clicked (PsppireVarSheet *var_sheet, gint dict_index,
+
+static void
+on_data_sheet_var_double_clicked (JmdSheet *data_sheet, gint dict_index,
PsppireDataEditor *de)
{
- PsppireDataSheet *data_sheet;
-
+
gtk_notebook_set_current_page (GTK_NOTEBOOK (de),
- PSPPIRE_DATA_EDITOR_DATA_VIEW);
-
- data_sheet = psppire_data_editor_get_active_data_sheet (de);
- psppire_data_sheet_goto_variable (data_sheet, dict_index);
+ PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
- return TRUE;
+ jmd_sheet_scroll_to (JMD_SHEET (de->var_sheet), -1, dict_index);
}
+
+
/* Refreshes 'de->cell_ref_label' and 'de->datum_entry' from the currently
active cell or cells. */
static void
refresh_entry (PsppireDataEditor *de)
{
- PsppireDataSheet *data_sheet = psppire_data_editor_get_active_data_sheet (de);
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
-
- gchar *ref_cell_text;
- GList *selected_columns, *iter;
- struct variable *var;
- gint n_cases;
- gint n_vars;
-
- selected_columns = pspp_sheet_selection_get_selected_columns (selection);
- n_vars = 0;
- var = NULL;
- for (iter = selected_columns; iter != NULL; iter = iter->next)
- {
- PsppSheetViewColumn *column = iter->data;
- struct variable *v = g_object_get_data (G_OBJECT (column), "variable");
- if (v != NULL)
- {
- var = v;
- n_vars++;
- }
- }
- g_list_free (selected_columns);
-
- n_cases = pspp_sheet_selection_count_selected_rows (selection);
- if (n_cases > 0)
- {
- /* The final row is selectable but it isn't a case (it's just used to add
- more cases), so don't count it. */
- GtkTreePath *path;
- gint case_count;
-
- case_count = psppire_data_store_get_case_count (de->data_store);
- path = gtk_tree_path_new_from_indices (case_count, -1);
- if (pspp_sheet_selection_path_is_selected (selection, path))
- n_cases--;
- gtk_tree_path_free (path);
- }
-
- ref_cell_text = NULL;
- if (n_cases == 1 && n_vars == 1)
- {
- PsppireValueEntry *value_entry = PSPPIRE_VALUE_ENTRY (de->datum_entry);
- struct range_set *selected_rows;
- gboolean show_value_labels;
- union value value;
- int width;
- gint row;
-
- selected_rows = pspp_sheet_selection_get_range_set (selection);
- row = range_set_scan (selected_rows, 0);
- range_set_destroy (selected_rows);
-
- ref_cell_text = g_strdup_printf ("%d : %s", row + 1, var_get_name (var));
-
- show_value_labels = psppire_data_sheet_get_value_labels (data_sheet);
-
- psppire_value_entry_set_variable (value_entry, var);
- psppire_value_entry_set_show_value_label (value_entry,
- show_value_labels);
-
- width = var_get_width (var);
- value_init (&value, width);
- datasheet_get_value (de->data_store->datasheet,
- row, var_get_case_index (var), &value);
- psppire_value_entry_set_value (value_entry, &value, width);
- value_destroy (&value, width);
-
- gtk_widget_set_sensitive (de->datum_entry, TRUE);
- }
- else
- {
- if (n_cases == 0 || n_vars == 0)
- {
- ref_cell_text = NULL;
- }
- else
- {
- struct string s;
-
- /* The glib string library does not understand the ' printf modifier
- on all platforms, but the "struct string" library does (because
- Gnulib fixes that problem), so use the latter. */
- ds_init_empty (&s);
- ds_put_format (&s, ngettext ("%'d case", "%'d cases", n_cases),
- n_cases);
- ds_put_byte (&s, ' ');
- ds_put_unichar (&s, 0xd7); /* U+00D7 MULTIPLICATION SIGN */
- ds_put_byte (&s, ' ');
- ds_put_format (&s, ngettext ("%'d variable", "%'d variables",
- n_vars),
- n_vars);
- ref_cell_text = ds_steal_cstr (&s);
- }
-
- psppire_value_entry_set_variable (PSPPIRE_VALUE_ENTRY (de->datum_entry),
- NULL);
- gtk_entry_set_text (
- GTK_ENTRY (gtk_bin_get_child (GTK_BIN (de->datum_entry))), "");
- gtk_widget_set_sensitive (de->datum_entry, FALSE);
- }
+ union value val;
+ gint row, col;
+ jmd_sheet_get_active_cell (JMD_SHEET (de->data_sheet), &col, &row);
- gtk_label_set_label (GTK_LABEL (de->cell_ref_label),
- ref_cell_text ? ref_cell_text : "");
- g_free (ref_cell_text);
-}
+ const struct variable *var = psppire_dict_get_variable (de->dict, col);
+ psppire_value_entry_set_variable (PSPPIRE_VALUE_ENTRY (de->datum_entry), var);
-static void
-on_datum_entry_activate (PsppireValueEntry *entry, PsppireDataEditor *de)
-{
- PsppireDataSheet *data_sheet = psppire_data_editor_get_active_data_sheet (de);
- struct variable *var;
- union value value;
- int width;
- gint row;
-
- row = psppire_data_sheet_get_current_case (data_sheet);
- var = psppire_data_sheet_get_current_variable (data_sheet);
- if (row < 0 || !var)
+ int width = var_get_width (var);
+ if (! psppire_data_store_get_value (PSPPIRE_DATA_STORE (de->data_store),
+ row, var, &val))
return;
- width = var_get_width (var);
- value_init (&value, width);
- if (psppire_value_entry_get_value (PSPPIRE_VALUE_ENTRY (de->datum_entry),
- &value, width))
- psppire_data_store_set_value (de->data_store, row, var, &value);
- value_destroy (&value, width);
+ psppire_value_entry_set_value (PSPPIRE_VALUE_ENTRY (de->datum_entry),
+ &val, width);
+ value_destroy (&val, width);
}
static void
-on_data_sheet_selection_changed (PsppSheetSelection *selection,
- PsppireDataEditor *de)
+on_datum_entry_activate (PsppireValueEntry *entry, PsppireDataEditor *de)
{
- /* In a split view, ensure that only a single data sheet has a nonempty
- selection. */
- if (de->split
- && pspp_sheet_selection_count_selected_rows (selection)
- && pspp_sheet_selection_count_selected_columns (selection))
- {
- PsppireDataSheet *ds;
- int i;
-
- FOR_EACH_DATA_SHEET (ds, i, de)
- {
- PsppSheetSelection *s;
-
- s = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ds));
- if (s != selection)
- pspp_sheet_selection_unselect_all (s);
- }
- }
-
- refresh_entry (de);
}
-/* Ensures that rows in the right-hand panes in the split view have the same
- row height as the left-hand panes. Otherwise, the rows in the right-hand
- pane tend to be smaller, because the right-hand pane doesn't have buttons
- for case numbers. */
-static void
-on_data_sheet_fixed_height_notify (PsppireDataSheet *ds,
- GParamSpec *pspec,
- PsppireDataEditor *de)
-{
- enum
- {
- TL = GTK_XPANED_TOP_LEFT,
- TR = GTK_XPANED_TOP_RIGHT,
- BL = GTK_XPANED_BOTTOM_LEFT,
- BR = GTK_XPANED_BOTTOM_RIGHT
- };
-
- int fixed_height = pspp_sheet_view_get_fixed_height (PSPP_SHEET_VIEW (ds));
-
- pspp_sheet_view_set_fixed_height (PSPP_SHEET_VIEW (de->data_sheets[TR]),
- fixed_height);
- pspp_sheet_view_set_fixed_height (PSPP_SHEET_VIEW (de->data_sheets[BR]),
- fixed_height);
-}
static void
disconnect_data_sheets (PsppireDataEditor *de)
{
- PsppireDataSheet *ds;
- int i;
-
- FOR_EACH_DATA_SHEET (ds, i, de)
- {
- PsppSheetSelection *selection;
-
- if (ds == NULL)
- {
- /* This can only happen if 'dispose' runs more than once. */
- continue;
- }
-
- if (i == GTK_XPANED_TOP_LEFT)
- g_signal_handlers_disconnect_by_func (
- ds, G_CALLBACK (on_data_sheet_fixed_height_notify), de);
-
- g_signal_handlers_disconnect_by_func (
- ds, G_CALLBACK (refresh_entry), de);
- g_signal_handlers_disconnect_by_func (
- ds, G_CALLBACK (on_data_sheet_var_double_clicked), de);
-
- selection = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ds));
- g_signal_handlers_disconnect_by_func (
- selection, G_CALLBACK (on_data_sheet_selection_changed), de);
-
- de->data_sheets[i] = NULL;
- }
-}
-
-static GtkWidget *
-make_data_sheet (PsppireDataEditor *de, GtkTreeViewGridLines grid_lines,
- gboolean show_value_labels)
-{
- PsppSheetSelection *selection;
- GtkWidget *ds;
-
- ds = psppire_data_sheet_new ();
- pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (ds), grid_lines);
- psppire_data_sheet_set_value_labels (PSPPIRE_DATA_SHEET (ds),
- show_value_labels);
-
- g_signal_connect_swapped (ds, "notify::value-labels",
- G_CALLBACK (refresh_entry), de);
- g_signal_connect (ds, "var-double-clicked",
- G_CALLBACK (on_data_sheet_var_double_clicked), de);
-
- selection = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (ds));
- g_signal_connect (selection, "changed",
- G_CALLBACK (on_data_sheet_selection_changed), de);
-
- return ds;
}
-static GtkWidget *
-make_single_datasheet (PsppireDataEditor *de, GtkTreeViewGridLines grid_lines,
- gboolean show_value_labels)
+/* Called when the active cell or the selection in the data sheet changes */
+static void
+on_data_selection_change (PsppireDataEditor *de, JmdRange *sel)
{
- GtkWidget *data_sheet_scroller;
-
- de->data_sheets[0] = make_data_sheet (de, grid_lines, show_value_labels);
- de->data_sheets[1] = de->data_sheets[2] = de->data_sheets[3] = NULL;
-
- /* Put data sheet in scroller. */
- data_sheet_scroller = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (data_sheet_scroller),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_container_add (GTK_CONTAINER (data_sheet_scroller), de->data_sheets[0]);
+ gchar *ref_cell_text = NULL;
- return data_sheet_scroller;
-}
+ gint n_cases = abs (sel->end_y - sel->start_y) + 1;
+ gint n_vars = abs (sel->end_x - sel->start_x) + 1;
-static GtkWidget *
-make_split_datasheet (PsppireDataEditor *de, GtkTreeViewGridLines grid_lines,
- gboolean show_value_labels)
-{
- /* Panes, in the order in which we want to create them. */
- enum
+ if (n_cases == 1 && n_vars == 1)
{
- TL, /* top left */
- TR, /* top right */
- BL, /* bottom left */
- BR /* bottom right */
- };
-
- PsppSheetView *ds[4];
- GtkXPaned *xpaned;
- int i;
-
- xpaned = GTK_XPANED (gtk_xpaned_new ());
+ /* A single cell is selected */
+ const struct variable *var = psppire_dict_get_variable (de->dict, sel->start_x);
- for (i = 0; i < 4; i++)
+ if (var)
+ ref_cell_text = g_strdup_printf (_("%d : %s"),
+ sel->start_y + 1, var_get_name (var));
+ }
+ else
{
- GtkAdjustment *hadjust, *vadjust;
- GtkPolicyType hpolicy, vpolicy;
- GtkWidget *scroller;
-
- de->data_sheets[i] = make_data_sheet (de, grid_lines, show_value_labels);
- ds[i] = PSPP_SHEET_VIEW (de->data_sheets[i]);
-
- if (i == BL)
- hadjust = pspp_sheet_view_get_hadjustment (ds[TL]);
- else if (i == BR)
- hadjust = pspp_sheet_view_get_hadjustment (ds[TR]);
- else
- hadjust = NULL;
-
- if (i == TR)
- vadjust = pspp_sheet_view_get_vadjustment (ds[TL]);
- else if (i == BR)
- vadjust = pspp_sheet_view_get_vadjustment (ds[BL]);
- else
- vadjust = NULL;
-
- scroller = gtk_scrolled_window_new (hadjust, vadjust);
- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroller),
- GTK_SHADOW_ETCHED_IN);
- hpolicy = i == TL || i == TR ? GTK_POLICY_NEVER : GTK_POLICY_ALWAYS;
- vpolicy = i == TL || i == BL ? GTK_POLICY_NEVER : GTK_POLICY_ALWAYS;
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroller),
- hpolicy, vpolicy);
- gtk_container_add (GTK_CONTAINER (scroller), GTK_WIDGET (ds[i]));
-
- switch (i)
- {
- case TL:
- gtk_xpaned_pack_top_left (xpaned, scroller, TRUE, TRUE);
- break;
-
- case TR:
- gtk_xpaned_pack_top_right (xpaned, scroller, TRUE, TRUE);
- break;
-
- case BL:
- gtk_xpaned_pack_bottom_left (xpaned, scroller, TRUE, TRUE);
- break;
-
- case BR:
- gtk_xpaned_pack_bottom_right (xpaned, scroller, TRUE, TRUE);
- break;
-
- default:
- g_warn_if_reached ();
- }
+ struct string s;
+
+ /* The glib string library does not understand the ' printf modifier
+ on all platforms, but the "struct string" library does (because
+ Gnulib fixes that problem), so use the latter. */
+ ds_init_empty (&s);
+ ds_put_format (&s, ngettext ("%'d case", "%'d cases", n_cases),
+ n_cases);
+ ds_put_byte (&s, ' ');
+ ds_put_unichar (&s, 0xd7); /* U+00D7 MULTIPLICATION SIGN */
+ ds_put_byte (&s, ' ');
+ ds_put_format (&s, ngettext ("%'d variable", "%'d variables",
+ n_vars),
+ n_vars);
+ ref_cell_text = ds_steal_cstr (&s);
}
+
+ gtk_label_set_label (GTK_LABEL (de->cell_ref_label),
+ ref_cell_text ? ref_cell_text : "");
+
+ g_free (ref_cell_text);
+}
- /* Bottom sheets don't display variable names. */
- pspp_sheet_view_set_headers_visible (ds[BL], FALSE);
- pspp_sheet_view_set_headers_visible (ds[BR], FALSE);
-
- /* Right sheets don't display case numbers. */
- psppire_data_sheet_set_case_numbers (PSPPIRE_DATA_SHEET (ds[TR]), FALSE);
- psppire_data_sheet_set_case_numbers (PSPPIRE_DATA_SHEET (ds[BR]), FALSE);
- g_signal_connect (ds[TL], "notify::fixed-height",
- G_CALLBACK (on_data_sheet_fixed_height_notify), de);
+static void set_font_recursively (GtkWidget *w, gpointer data);
- return GTK_WIDGET (xpaned);
-}
+gchar *myconvfunc (GtkTreeModel *m, gint col, gint row, const GValue *v);
+void myreversefunc (GtkTreeModel *model, gint col, gint row, const gchar *in, GValue *out);
-static void set_font_recursively (GtkWidget *w, gpointer data);
static void
psppire_data_editor_init (PsppireDataEditor *de)
{
- GtkWidget *var_sheet_scroller;
GtkWidget *hbox;
gchar *fontname = NULL;
gtk_box_pack_start (GTK_BOX (hbox), de->datum_entry, TRUE, TRUE, 0);
de->split = FALSE;
- de->datasheet_vbox_widget
- = make_single_datasheet (de, GTK_TREE_VIEW_GRID_LINES_BOTH, FALSE);
-
+ de->data_sheet = jmd_sheet_new ();
+ jmd_sheet_body_set_conversion_func
+ (JMD_SHEET_BODY (JMD_SHEET(de->data_sheet)->selected_body),
+ myconvfunc, myreversefunc);
+
+ GtkWidget *data_button = jmd_sheet_get_button (JMD_SHEET (de->data_sheet));
+ gtk_button_set_label (GTK_BUTTON (data_button), _("Case"));
de->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_box_pack_start (GTK_BOX (de->vbox), hbox, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (de->vbox), de->datasheet_vbox_widget,
- TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (de->vbox), de->data_sheet, TRUE, TRUE, 0);
+
+ g_signal_connect_swapped (de->data_sheet, "selection-changed",
+ G_CALLBACK (on_data_selection_change), de);
+
gtk_notebook_append_page (GTK_NOTEBOOK (de), de->vbox,
gtk_label_new_with_mnemonic (_("Data View")));
gtk_widget_show_all (de->vbox);
- de->var_sheet = GTK_WIDGET (psppire_var_sheet_new ());
- pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (de->var_sheet),
- GTK_TREE_VIEW_GRID_LINES_BOTH);
- var_sheet_scroller = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (var_sheet_scroller),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_container_add (GTK_CONTAINER (var_sheet_scroller), de->var_sheet);
- gtk_widget_show_all (var_sheet_scroller);
- gtk_notebook_append_page (GTK_NOTEBOOK (de), var_sheet_scroller,
+ de->var_sheet = g_object_new (JMD_TYPE_SHEET, NULL);
+
+ PsppireVarSheetHeader *vsh = g_object_new (PSPPIRE_TYPE_VAR_SHEET_HEADER, NULL);
+
+ g_object_set (de->var_sheet,
+ "hmodel", vsh,
+ "select-renderer-func", select_renderer_func,
+ NULL);
+
+
+ GtkWidget *var_button = jmd_sheet_get_button (JMD_SHEET (de->var_sheet));
+ gtk_button_set_label (GTK_BUTTON (var_button), _("Variable"));
+
+ gtk_notebook_append_page (GTK_NOTEBOOK (de), de->var_sheet,
gtk_label_new_with_mnemonic (_("Variable View")));
- g_signal_connect (de->var_sheet, "var-double-clicked",
+ gtk_widget_show_all (de->var_sheet);
+
+ g_signal_connect (de->var_sheet, "row-header-double-clicked",
G_CALLBACK (on_var_sheet_var_double_clicked), de);
+ g_signal_connect (de->data_sheet, "column-header-double-clicked",
+ G_CALLBACK (on_data_sheet_var_double_clicked), de);
+
g_object_set (de, "can-focus", FALSE, NULL);
if (psppire_conf_get_string (psppire_conf_new (),
void
psppire_data_editor_show_grid (PsppireDataEditor *de, gboolean grid_visible)
{
- GtkTreeViewGridLines grid;
- PsppireDataSheet *data_sheet;
- int i;
-
- grid = (grid_visible
- ? GTK_TREE_VIEW_GRID_LINES_BOTH
- : GTK_TREE_VIEW_GRID_LINES_NONE);
-
- FOR_EACH_DATA_SHEET (data_sheet, i, de)
- pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (data_sheet), grid);
- pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (de->var_sheet), grid);
+ g_object_set (JMD_SHEET (de->var_sheet), "gridlines", grid_visible, NULL);
+ g_object_set (JMD_SHEET (de->data_sheet), "gridlines", grid_visible, NULL);
}
void
psppire_data_editor_split_window (PsppireDataEditor *de, gboolean split)
{
- GtkTreeViewGridLines grid_lines;
- gboolean labels;
-
if (split == de->split)
return;
-
- grid_lines = pspp_sheet_view_get_grid_lines (
- PSPP_SHEET_VIEW (de->data_sheets[0]));
- labels = psppire_data_sheet_get_value_labels (PSPPIRE_DATA_SHEET (
- de->data_sheets[0]));
-
disconnect_data_sheets (de);
- if (de->old_vbox_widget)
- g_object_unref (de->old_vbox_widget);
- de->old_vbox_widget = de->datasheet_vbox_widget;
- g_object_ref (de->old_vbox_widget);
- /* FIXME: old_vbox_widget needs to be unreffed in dispose.
- (currently it seems to provoke an error if I do that.
- I don't know why. */
- gtk_container_remove (GTK_CONTAINER (de->vbox), de->datasheet_vbox_widget);
-
- if (split)
- de->datasheet_vbox_widget = make_split_datasheet (de, grid_lines, labels);
- else
- de->datasheet_vbox_widget = make_single_datasheet (de, grid_lines, labels);
psppire_data_editor_refresh_model (de);
- gtk_box_pack_start (GTK_BOX (de->vbox), de->datasheet_vbox_widget,
- TRUE, TRUE, 0);
gtk_widget_show_all (de->vbox);
if (de->font)
void
psppire_data_editor_goto_variable (PsppireDataEditor *de, gint dict_index)
{
- PsppireDataSheet *data_sheet;
-
- switch (gtk_notebook_get_current_page (GTK_NOTEBOOK (de)))
- {
- case PSPPIRE_DATA_EDITOR_DATA_VIEW:
- data_sheet = psppire_data_editor_get_active_data_sheet (de);
- psppire_data_sheet_goto_variable (data_sheet, dict_index);
- break;
-
- case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
- psppire_var_sheet_goto_variable (PSPPIRE_VAR_SHEET (de->var_sheet),
- dict_index);
- break;
- }
-}
-
-/* Returns the "active" data sheet in DE. If DE is in single-paned mode, this
- is the only data sheet. If DE is in split mode (showing four data sheets),
- this is the focused data sheet or, if none is focused, the data sheet with
- selected cells or, if none has selected cells, the upper-left data sheet. */
-PsppireDataSheet *
-psppire_data_editor_get_active_data_sheet (PsppireDataEditor *de)
-{
- if (de->split)
- {
- PsppireDataSheet *data_sheet;
- GtkWidget *scroller;
- int i;
-
- /* If one of the datasheet's scrollers is focused, choose that one. */
- scroller = gtk_container_get_focus_child (
- GTK_CONTAINER (de->datasheet_vbox_widget));
- if (scroller != NULL)
- return PSPPIRE_DATA_SHEET (gtk_bin_get_child (GTK_BIN (scroller)));
-
- /* Otherwise if there's a nonempty selection in some data sheet, choose
- that one. */
- FOR_EACH_DATA_SHEET (data_sheet, i, de)
- {
- PsppSheetSelection *selection;
-
- selection = pspp_sheet_view_get_selection (
- PSPP_SHEET_VIEW (data_sheet));
- if (pspp_sheet_selection_count_selected_rows (selection)
- && pspp_sheet_selection_count_selected_columns (selection))
- return data_sheet;
- }
- }
-
- return PSPPIRE_DATA_SHEET (de->data_sheets[0]);
}
#include <gtk/gtk.h>
#include "psppire-data-store.h"
-#include "ui/gui/pspp-sheet-view.h"
G_BEGIN_DECLS
/* Variable sheet tab. */
GtkWidget *var_sheet;
+ GtkWidget *data_sheet;
/* Data sheet tab. */
GtkWidget *vbox; /* Top-level widget in tab. */
GtkWidget *cell_ref_label; /* GtkLabel that shows selected case and var. */
GtkWidget *datum_entry; /* PsppireValueEntry for editing current cell. */
- GtkWidget *datasheet_vbox_widget; /* ->vbox child that holds data sheets. */
- GtkWidget *data_sheets[4]; /* Normally one data sheet; four, if split. */
+
gboolean split; /* True if data sheets are split. */
/* UI manager for whichever var or data sheet is currently in use. */
+++ /dev/null
-/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2011, 2012, 2013 Free Software Foundation, Inc.
-
- 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 <config.h>
-
-#include "ui/gui/psppire-data-sheet.h"
-
-#include "data/case-map.h"
-#include "data/casereader.h"
-#include "data/casewriter.h"
-#include "data/data-out.h"
-#include "data/datasheet.h"
-#include "data/format.h"
-#include "data/value-labels.h"
-#include "libpspp/intern.h"
-#include "libpspp/range-set.h"
-#include "ui/gui/executor.h"
-#include "ui/gui/find-dialog.h"
-#include "ui/gui/goto-case-dialog.h"
-#include "ui/gui/builder-wrapper.h"
-#include "ui/gui/helper.h"
-#include "ui/gui/pspp-sheet-selection.h"
-#include "ui/gui/psppire-cell-renderer-button.h"
-#include "ui/gui/psppire-data-store.h"
-#include "ui/gui/psppire-data-window.h"
-#include "ui/gui/psppire-dialog-action-var-info.h"
-#include "ui/gui/psppire-empty-list-store.h"
-#include "ui/gui/psppire-marshal.h"
-
-#include "gl/intprops.h"
-#include "gl/xalloc.h"
-
-#include <gettext.h>
-#define _(msgid) gettext (msgid)
-#define N_(msgid) msgid
-
-static void psppire_data_sheet_dispose (GObject *);
-static void psppire_data_sheet_unset_data_store (PsppireDataSheet *);
-
-static void psppire_data_sheet_update_clip_actions (PsppireDataSheet *);
-static void psppire_data_sheet_update_primary_selection (PsppireDataSheet *,
- gboolean should_own);
-static void psppire_data_sheet_set_clip (PsppireDataSheet *, gboolean cut);
-
-static void on_selection_changed (PsppSheetSelection *, gpointer);
-static void on_owner_change (GtkClipboard *, GdkEventOwnerChange *, gpointer);
-static void psppire_data_sheet_clip_received_cb (GtkClipboard *,
- GtkSelectionData *, gpointer);
-
-G_DEFINE_TYPE (PsppireDataSheet, psppire_data_sheet, PSPP_TYPE_SHEET_VIEW);
-
-static gboolean
-get_tooltip_location (GtkWidget *widget, GtkTooltip *tooltip,
- gint wx, gint wy,
- size_t *row, PsppSheetViewColumn **columnp)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
- gint bx, by;
- GtkTreePath *path;
- GtkTreeIter iter;
- PsppSheetViewColumn *tree_column;
- GtkTreeModel *tree_model;
- bool ok;
-
- /* Check that WIDGET is really visible on the screen before we
- do anything else. This is a bug fix for a sticky situation:
- when text_data_import_assistant() returns, it frees the data
- necessary to compose the tool tip message, but there may be
- a tool tip under preparation at that point (even if there is
- no visible tool tip) that will call back into us a little
- bit later. Perhaps the correct solution to this problem is
- to make the data related to the tool tips part of a GObject
- that only gets destroyed when all references are released,
- but this solution appears to be effective too. */
- if (!gtk_widget_get_mapped (widget))
- return FALSE;
-
- pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view,
- wx, wy, &bx, &by);
- if (!pspp_sheet_view_get_path_at_pos (tree_view, bx, by,
- &path, &tree_column, NULL, NULL))
- return FALSE;
-
- *columnp = tree_column;
-
- pspp_sheet_view_set_tooltip_cell (tree_view, tooltip, path, tree_column,
- NULL);
-
- tree_model = pspp_sheet_view_get_model (tree_view);
- ok = gtk_tree_model_get_iter (tree_model, &iter, path);
- gtk_tree_path_free (path);
- if (!ok)
- return FALSE;
-
- *row = GPOINTER_TO_INT (iter.user_data);
- return TRUE;
-}
-
-static gboolean
-on_query_tooltip (GtkWidget *widget, gint wx, gint wy,
- gboolean keyboard_mode UNUSED,
- GtkTooltip *tooltip, gpointer data UNUSED)
-{
- PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (widget);
- PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
- PsppSheetViewColumn *column;
- struct variable *var;
- const char *label;
- union value v;
- size_t row;
- int width;
-
- g_return_val_if_fail (data_store != NULL, FALSE);
- g_return_val_if_fail (data_store->datasheet != NULL, FALSE);
-
- if (!get_tooltip_location (widget, tooltip, wx, wy, &row, &column))
- return FALSE;
-
- var = g_object_get_data (G_OBJECT (column), "variable");
- if (var == NULL)
- {
- if (g_object_get_data (G_OBJECT (column), "new-var-column") == NULL)
- return FALSE;
-
- gtk_tooltip_set_text (tooltip,
- _("Enter a number to add a new variable."));
- return TRUE;
- }
- else if (row >= datasheet_get_n_rows (data_store->datasheet))
- {
- gtk_tooltip_set_text (tooltip, _("Enter a number to add a new case."));
- return TRUE;
- }
-
- width = var_get_width (var);
-
- value_init (&v, width);
- datasheet_get_value (data_store->datasheet, row, var_get_case_index (var),
- &v);
-
- label = var_lookup_value_label (var, &v);
- if (label != NULL)
- {
- if (data_sheet->show_value_labels)
- {
- char *s = value_to_text (v, var);
- gtk_tooltip_set_text (tooltip, s);
- free (s);
- }
- else
- gtk_tooltip_set_text (tooltip, label);
- }
- value_destroy (&v, width);
-
- return label != NULL;
-}
-
-static void
-render_row_number_cell (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer store_)
-{
- PsppireDataStore *store = store_;
- GValue gvalue = { 0, };
- gint row = GPOINTER_TO_INT (iter->user_data);
-
- g_return_if_fail (store->datasheet);
-
- g_value_init (&gvalue, G_TYPE_INT);
- g_value_set_int (&gvalue, row + 1);
- g_object_set_property (G_OBJECT (cell), "label", &gvalue);
- g_value_unset (&gvalue);
-
- if (row < datasheet_get_n_rows (store->datasheet))
- g_object_set (cell, "editable", TRUE, NULL);
- else
- g_object_set (cell, "editable", FALSE, NULL);
-
- g_object_set (cell,
- "slash", psppire_data_store_filtered (store, row),
- NULL);
-}
-
-static void
-on_row_number_clicked (PsppireCellRendererButton *button,
- gchar *path_string,
- PsppSheetView *sheet_view)
-{
- PsppSheetSelection *selection;
- GtkTreePath *path;
-
- path = gtk_tree_path_new_from_string (path_string);
-
- selection = pspp_sheet_view_get_selection (sheet_view);
- pspp_sheet_selection_unselect_all (selection);
- pspp_sheet_selection_select_path (selection, path);
- pspp_sheet_selection_select_all_columns (selection);
-
- gtk_tree_path_free (path);
-}
-
-static void
-make_row_number_column (PsppireDataSheet *data_sheet,
- PsppireDataStore *ds)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppSheetViewColumn *column;
- GtkCellRenderer *renderer;
-
- renderer = psppire_cell_renderer_button_new ();
- g_object_set (renderer, "xalign", 1.0, NULL);
- g_signal_connect (renderer, "clicked", G_CALLBACK (on_row_number_clicked),
- sheet_view);
-
- column = pspp_sheet_view_column_new_with_attributes (_("Case"),
- renderer, NULL);
- pspp_sheet_view_column_set_selectable (column, TRUE);
- pspp_sheet_view_column_set_row_head (column, TRUE);
- pspp_sheet_view_column_set_tabbable (column, FALSE);
- pspp_sheet_view_column_set_clickable (column, TRUE);
- pspp_sheet_view_column_set_cell_data_func (
- column, renderer, render_row_number_cell, ds, NULL);
- pspp_sheet_view_column_set_fixed_width (column, 50);
- pspp_sheet_view_column_set_visible (column, data_sheet->show_case_numbers);
- pspp_sheet_view_append_column (sheet_view, column);
-}
-
-static void
-render_data_cell (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer data_sheet_)
-{
- PsppireDataSheet *data_sheet = data_sheet_;
- PsppireDataStore *store = psppire_data_sheet_get_data_store (data_sheet);
- struct variable *var;
- gchar *string;
- gint row;
-
- double xalign;
-
- row = GPOINTER_TO_INT (iter->user_data);
- var = g_object_get_data (G_OBJECT (tree_column), "variable");
-
- string = psppire_data_store_get_string (store, row, var,
- data_sheet->show_value_labels);
- if (string != NULL)
- {
- GValue gvalue = { 0 };
-
- g_value_init (&gvalue, G_TYPE_STRING);
- g_value_take_string (&gvalue, string);
- g_object_set_property (G_OBJECT (cell), "text", &gvalue);
- g_value_unset (&gvalue);
- }
- else
- g_object_set (G_OBJECT (cell), "text", "", NULL);
-
- switch (var_get_alignment (var))
- {
- case ALIGN_LEFT: xalign = 0.0; break;
- case ALIGN_RIGHT: xalign = 1.0; break;
- case ALIGN_CENTRE: xalign = 0.5; break;
- default: xalign = 0.0; break;
- }
- g_object_set (cell,
- "xalign", xalign,
- "editable", TRUE,
- NULL);
-}
-
-static gint
-get_string_width (PsppSheetView *treeview, GtkCellRenderer *renderer,
- const char *string)
-{
- gint width;
- g_object_set (G_OBJECT (renderer), "text", string, (void *) NULL);
- gtk_cell_renderer_get_preferred_width (renderer, GTK_WIDGET (treeview),
- NULL, &width);
-
- return width;
-}
-
-static gint
-get_monospace_width (PsppSheetView *treeview, GtkCellRenderer *renderer,
- size_t char_cnt)
-{
- struct string s;
- gint width;
-
- ds_init_empty (&s);
- ds_put_byte_multiple (&s, '0', char_cnt);
- ds_put_byte (&s, ' ');
- width = get_string_width (treeview, renderer, ds_cstr (&s));
- ds_destroy (&s);
-
- return width;
-}
-
-static void
-on_data_column_editing_started (GtkCellRenderer *cell,
- GtkCellEditable *editable,
- const gchar *path,
- gpointer user_data)
-{
- PsppSheetViewColumn *column = g_object_get_data (G_OBJECT (cell), "column");
- PsppireDataSheet *data_sheet = g_object_get_data (G_OBJECT (cell), "data-sheet");
- PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
- struct variable *var;
-
- g_return_if_fail (column);
- g_return_if_fail (data_sheet);
- g_return_if_fail (data_store);
-
-
- g_object_ref (editable);
- g_object_set_data_full (G_OBJECT (cell), "data-sheet-editable",
- editable, g_object_unref);
-
- var = g_object_get_data (G_OBJECT (column), "variable");
- g_return_if_fail (var);
-
- if (var_has_value_labels (var) && GTK_IS_COMBO_BOX (editable))
- {
- const struct val_labs *labels = var_get_value_labels (var);
- const struct val_lab **vls = val_labs_sorted (labels);
- size_t n_vls = val_labs_count (labels);
- GtkListStore *list_store;
- int i;
-
- list_store = gtk_list_store_new (1, G_TYPE_STRING);
- for (i = 0; i < n_vls; ++i)
- {
- const struct val_lab *vl = vls[i];
- GtkTreeIter iter;
-
- gtk_list_store_append (list_store, &iter);
- gtk_list_store_set (list_store, &iter,
- 0, val_lab_get_label (vl),
- -1);
- }
- free (vls);
-
- gtk_combo_box_set_model (GTK_COMBO_BOX (editable),
- GTK_TREE_MODEL (list_store));
- g_object_unref (list_store);
- }
-}
-
-static void
-scroll_to_bottom (GtkWidget *widget,
- GtkRequisition *requisition,
- gpointer unused UNUSED)
-{
- PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (widget);
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (widget);
- GtkAdjustment *vadjust;
-
- vadjust = pspp_sheet_view_get_vadjustment (sheet_view);
- gtk_adjustment_set_value (vadjust, gtk_adjustment_get_upper (vadjust));
-
- if (data_sheet->scroll_to_bottom_signal)
- {
- g_signal_handler_disconnect (data_sheet,
- data_sheet->scroll_to_bottom_signal);
- data_sheet->scroll_to_bottom_signal = 0;
- }
-}
-
-static void
-on_data_column_edited (GtkCellRendererText *cell,
- gchar *path_string,
- gchar *new_text,
- gpointer user_data)
-{
- PsppSheetViewColumn *column = g_object_get_data (G_OBJECT (cell), "column");
- PsppireDataSheet *data_sheet = g_object_get_data (G_OBJECT (cell), "data-sheet");
- PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
- GtkEditable *editable;
- struct variable *var;
- GtkTreePath *path;
- gboolean is_val_lab;
- gboolean new_row;
- gint row;
-
- path = gtk_tree_path_new_from_string (path_string);
- row = gtk_tree_path_get_indices (path)[0];
- gtk_tree_path_free (path);
-
- var = g_object_get_data (G_OBJECT (column), "variable");
-
- new_row = row == psppire_data_store_get_case_count (data_store);
- if (new_row && new_text[0] == '\0')
- return;
-
- editable = g_object_steal_data (G_OBJECT (cell), "data-sheet-editable");
- g_return_if_fail (editable != NULL);
- is_val_lab = (GTK_IS_COMBO_BOX (editable)
- && gtk_combo_box_get_active (GTK_COMBO_BOX (editable)) >= 0);
- g_object_unref (editable);
-
- psppire_data_store_set_string (data_store, new_text, row, var, is_val_lab);
-
- if (new_row && !data_sheet->scroll_to_bottom_signal)
- {
- gtk_widget_queue_resize (GTK_WIDGET (data_sheet));
- data_sheet->scroll_to_bottom_signal =
- g_signal_connect (data_sheet, "size-allocate",
- G_CALLBACK (scroll_to_bottom), NULL);
- }
- else
- {
- /* We could be more specific about what to redraw, if it seems
- important for performance. */
- gtk_widget_queue_draw (GTK_WIDGET (data_sheet));
- }
-}
-
-static void
-scroll_to_right (GtkWidget *widget,
- PsppireDataSheet *data_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppSheetViewColumn *column, *prev;
- GList *columns, *iter;
-
- column = NULL;
- prev = NULL;
- columns = pspp_sheet_view_get_columns (sheet_view);
- for (iter = columns; iter; iter = iter->next)
- {
- PsppSheetViewColumn *c = iter->data;
- if (g_object_get_data (G_OBJECT (c), "new-var-column"))
- {
- column = c;
- break;
- }
- prev = c;
- }
- g_list_free (columns);
-
- if (column == NULL)
- return;
-
- pspp_sheet_view_scroll_to_cell (sheet_view, NULL, column, FALSE, 0, 0);
-
- if (prev)
- {
- GtkTreePath *path;
-
- pspp_sheet_view_get_cursor (sheet_view, &path, NULL);
- if (path)
- {
- pspp_sheet_view_set_cursor (sheet_view, path, prev, TRUE);
- gtk_tree_path_free (path);
- }
- }
-
- if (data_sheet->scroll_to_right_signal)
- {
- g_signal_handler_disconnect (widget, data_sheet->scroll_to_right_signal);
- data_sheet->scroll_to_right_signal = 0;
- }
-}
-
-static void
-on_new_variable_column_edited (GtkCellRendererText *cell,
- gchar *path_string,
- gchar *new_text,
- gpointer user_data)
-{
- PsppireDataSheet *data_sheet = g_object_get_data (G_OBJECT (cell), "data-sheet");
- PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
- PsppireDict *dict = data_store->dict;
- struct variable *var;
- GtkTreePath *path;
- char name[64];
- gint row;
-
- if (new_text[0] == '\0')
- {
- /* User didn't enter anything so don't create a variable. */
- return;
- }
-
- path = gtk_tree_path_new_from_string (path_string);
- row = gtk_tree_path_get_indices (path)[0];
- gtk_tree_path_free (path);
-
- if (!psppire_dict_generate_name (dict, name, sizeof name))
- return;
-
- var = psppire_dict_insert_variable (dict, psppire_dict_get_var_cnt (dict),
- name);
- g_return_if_fail (var != NULL);
-
- psppire_data_store_set_string (data_store, new_text, row, var, FALSE);
-
- if (!data_sheet->scroll_to_right_signal)
- {
- gtk_widget_queue_resize (GTK_WIDGET (data_sheet));
- data_sheet->scroll_to_right_signal =
- g_signal_connect_after (gtk_widget_get_toplevel (GTK_WIDGET (data_sheet)), "check-resize",
- G_CALLBACK (scroll_to_right), data_sheet);
- }
- else
- {
- /* We could be more specific about what to redraw, if it seems
- important for performance. */
- gtk_widget_queue_draw (GTK_WIDGET (data_sheet));
- }
-}
-
-static void
-calc_width_conversion (PsppireDataSheet *data_sheet,
- gint *base_width, gint *incr_width)
-{
- GtkCellRenderer *cell;
- gint w1, w10;
-
- cell = gtk_cell_renderer_text_new ();
- w1 = get_monospace_width (PSPP_SHEET_VIEW (data_sheet), cell, 1);
- w10 = get_monospace_width (PSPP_SHEET_VIEW (data_sheet), cell, 10);
- *incr_width = MAX (1, (w10 - w1) / 9);
- *base_width = MAX (0, w10 - *incr_width * 10);
- g_object_ref_sink (cell);
- g_object_unref (cell);
-}
-
-static gint
-display_width_from_pixel_width (PsppireDataSheet *data_sheet,
- gint pixel_width)
-{
- gint base_width, incr_width;
-
- calc_width_conversion (data_sheet, &base_width, &incr_width);
- return MAX ((pixel_width - base_width + incr_width / 2) / incr_width, 1);
-}
-
-static gint
-display_width_to_pixel_width (PsppireDataSheet *data_sheet,
- gint display_width,
- gint base_width,
- gint incr_width)
-{
- return base_width + incr_width * display_width;
-}
-
-static void
-on_data_column_resized (GObject *gobject,
- GParamSpec *pspec,
- gpointer user_data)
-{
- PsppireDataSheet *data_sheet = user_data;
- PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
- PsppSheetViewColumn *column = PSPP_SHEET_VIEW_COLUMN (gobject);
- struct variable *var;
- gint pixel_width;
- int display_width;
-
- if (data_store == NULL)
- return;
-
- pixel_width = pspp_sheet_view_column_get_width (column);
- if (pixel_width == pspp_sheet_view_column_get_fixed_width (column))
- {
- /* Short-circuit the expensive display_width_from_pixel_width()
- calculation, to make loading .sav files with 2000 columns visibly
- faster. */
- return;
- }
-
- var = g_object_get_data (G_OBJECT (column), "variable");
- display_width = display_width_from_pixel_width (data_sheet, pixel_width);
- var_set_display_width (var, display_width);
-}
-
-enum sort_order
- {
- SORT_ASCEND,
- SORT_DESCEND
- };
-
-static void
-do_sort (PsppireDataSheet *data_sheet, enum sort_order order)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
- PsppireDataWindow *pdw;
- GList *list, *iter;
- GString *syntax;
- int n_vars;
-
- pdw = psppire_data_window_for_data_store (data_sheet->data_store);
- g_return_if_fail (pdw != NULL);
-
- list = pspp_sheet_selection_get_selected_columns (selection);
-
- syntax = g_string_new ("SORT CASES BY");
- n_vars = 0;
- for (iter = list; iter; iter = iter->next)
- {
- PsppSheetViewColumn *column = iter->data;
- struct variable *var;
-
- var = g_object_get_data (G_OBJECT (column), "variable");
- if (var != NULL)
- {
- g_string_append_printf (syntax, " %s", var_get_name (var));
- n_vars++;
- }
- }
- if (n_vars > 0)
- {
- if (order == SORT_DESCEND)
- g_string_append (syntax, " (DOWN)");
- g_string_append_c (syntax, '.');
- execute_const_syntax_string (pdw, syntax->str);
- }
- g_string_free (syntax, TRUE);
-}
-
-static void
-on_sort_up (PsppireDataSheet *data_sheet)
-{
- do_sort (data_sheet, SORT_ASCEND);
-}
-
-static void
-on_sort_down (PsppireDataSheet *data_sheet)
-{
- do_sort (data_sheet, SORT_DESCEND);
-}
-
-static void
-do_data_column_popup_menu (PsppSheetViewColumn *column,
- guint button, guint32 time)
-{
- GtkWidget *sheet_view = pspp_sheet_view_column_get_tree_view (column);
- PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (sheet_view);
-
- gtk_menu_popup (GTK_MENU (data_sheet->column_popup_menu), NULL, NULL, NULL, NULL, button, time);
-}
-
-static void
-on_data_column_popup_menu (PsppSheetViewColumn *column,
- gpointer user_data UNUSED)
-{
- do_data_column_popup_menu (column, 0, gtk_get_current_event_time ());
-}
-
-static gboolean
-on_column_button_press_event (PsppSheetViewColumn *column,
- GdkEventButton *event,
- gpointer user_data UNUSED)
-{
- PsppSheetSelection *selection;
- PsppSheetView *sheet_view;
-
- sheet_view = PSPP_SHEET_VIEW (pspp_sheet_view_column_get_tree_view (
- column));
- g_return_val_if_fail (sheet_view != NULL, FALSE);
-
- selection = pspp_sheet_view_get_selection (sheet_view);
- g_return_val_if_fail (selection != NULL, FALSE);
-
- if (event->type == GDK_BUTTON_PRESS && event->button == 3)
- {
- do_data_column_popup_menu (column, event->button, event->time);
- return TRUE;
- }
- else if (event->type == GDK_2BUTTON_PRESS && event->button == 1)
- {
- PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (sheet_view);
- struct variable *var;
-
- var = g_object_get_data (G_OBJECT (column), "variable");
- if (var != NULL)
- {
- gboolean handled;
-
- g_signal_emit_by_name (data_sheet, "var-double-clicked",
- var_get_dict_index (var), &handled);
- return handled;
- }
- }
-
- return FALSE;
-}
-
-static gboolean
-on_data_column_query_tooltip (PsppSheetViewColumn *column,
- GtkTooltip *tooltip,
- gpointer user_data UNUSED)
-{
- struct variable *var;
- const char *text;
-
- var = g_object_get_data (G_OBJECT (column), "variable");
- g_return_val_if_fail (var != NULL, FALSE);
-
- text = var_has_label (var) ? var_get_label (var) : var_get_name (var);
- gtk_tooltip_set_text (tooltip, text);
-
- return TRUE;
-}
-
-static void
-add_data_column_cell_renderer (PsppireDataSheet *data_sheet,
- PsppSheetViewColumn *column)
-{
- GtkCellRenderer *cell;
- struct variable *var;
-
- var = g_object_get_data (G_OBJECT (column), "variable");
- g_return_if_fail (var != NULL);
-
- if (data_sheet->show_value_labels && var_has_value_labels (var))
- {
- cell = gtk_cell_renderer_combo_new ();
- g_object_set (G_OBJECT (cell),
- "has-entry", TRUE,
- "text-column", 0,
- NULL);
- }
- else
- cell = gtk_cell_renderer_text_new ();
-
- g_signal_connect (cell, "editing-started",
- G_CALLBACK (on_data_column_editing_started), NULL);
- g_signal_connect (cell, "edited", G_CALLBACK (on_data_column_edited), NULL);
-
- g_object_set_data (G_OBJECT (cell), "column", column);
- g_object_set_data (G_OBJECT (cell), "data-sheet", data_sheet);
-
- pspp_sheet_view_column_clear (column);
- pspp_sheet_view_column_pack_start (column, cell, TRUE);
-
- pspp_sheet_view_column_set_cell_data_func (
- column, cell, render_data_cell, data_sheet, NULL);
-}
-
-static PsppSheetViewColumn *
-make_data_column (PsppireDataSheet *data_sheet, gint dict_idx,
- gint base_width, gint incr_width)
-{
- PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
- struct variable *var;
- PsppSheetViewColumn *column;
- char *name;
- int width;
-
- var = psppire_dict_get_variable (data_store->dict, dict_idx);
-
- column = pspp_sheet_view_column_new ();
-
- name = escape_underscores (var_get_name (var));
- pspp_sheet_view_column_set_title (column, name);
- free (name);
-
- g_object_set_data (G_OBJECT (column), "variable", var);
-
- width = display_width_to_pixel_width (data_sheet,
- var_get_display_width (var),
- base_width, incr_width);
- pspp_sheet_view_column_set_min_width (column, 10);
- pspp_sheet_view_column_set_fixed_width (column, width);
- pspp_sheet_view_column_set_resizable (column, TRUE);
-
- pspp_sheet_view_column_set_clickable (column, TRUE);
- g_signal_connect (column, "notify::width",
- G_CALLBACK (on_data_column_resized), data_sheet);
-
- g_signal_connect (column, "button-press-event",
- G_CALLBACK (on_column_button_press_event),
- data_sheet);
- g_signal_connect (column, "query-tooltip",
- G_CALLBACK (on_data_column_query_tooltip), NULL);
- g_signal_connect (column, "popup-menu",
- G_CALLBACK (on_data_column_popup_menu), data_sheet);
-
- add_data_column_cell_renderer (data_sheet, column);
-
- return column;
-}
-
-static void
-make_new_variable_column (PsppireDataSheet *data_sheet,
- gint base_width, gint incr_width)
-{
- PsppSheetViewColumn *column;
- GtkCellRenderer *cell;
- int width;
-
- cell = gtk_cell_renderer_text_new ();
- g_object_set (cell, "editable", TRUE, NULL);
-
- g_signal_connect (cell, "edited", G_CALLBACK (on_new_variable_column_edited),
- NULL);
-
- column = pspp_sheet_view_column_new_with_attributes ("", cell, NULL);
- g_object_set_data (G_OBJECT (column), "new-var-column", column);
-
- width = display_width_to_pixel_width (data_sheet, 8, base_width, incr_width);
- pspp_sheet_view_column_set_min_width (column, 10);
- pspp_sheet_view_column_set_fixed_width (column, width);
- pspp_sheet_view_column_set_tabbable (column, FALSE);
-
- g_object_set_data (G_OBJECT (cell), "data-sheet", data_sheet);
- g_signal_connect (column, "button-press-event",
- G_CALLBACK (on_column_button_press_event),
- data_sheet);
- g_signal_connect (column, "popup-menu",
- G_CALLBACK (on_data_column_popup_menu), data_sheet);
-
- pspp_sheet_view_column_set_visible (column, data_sheet->may_create_vars);
-
- pspp_sheet_view_append_column (PSPP_SHEET_VIEW (data_sheet), column);
- data_sheet->new_variable_column = column;
-}
-
-static void
-psppire_data_sheet_model_changed (GObject *gobject,
- GParamSpec *pspec,
- gpointer user_data)
-{
- PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (gobject);
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppireDataStore *data_store;
-
- /* Remove old columns. */
- for (;;)
- {
- PsppSheetViewColumn *column = pspp_sheet_view_get_column (sheet_view, 0);
- if (column == NULL)
- break;
-
- pspp_sheet_view_remove_column (sheet_view, column);
- }
- data_sheet->new_variable_column = NULL;
-
- if (pspp_sheet_view_get_model (sheet_view) == NULL)
- {
- /* Don't create any columns at all if there's no model. Otherwise we'll
- create some columns as part of the "dispose" callback for the sheet
- view, which sets the model to NULL. That causes warnings to be
- logged and is obviously undesirable in any case. */
- return;
- }
-
- /* Add new columns. */
- data_store = psppire_data_sheet_get_data_store (data_sheet);
- if (data_store != NULL)
- {
- gint base_width, incr_width;
- int i;
-
- calc_width_conversion (data_sheet, &base_width, &incr_width);
-
- make_row_number_column (data_sheet, data_store);
- for (i = 0; i < psppire_dict_get_var_cnt (data_store->dict); i++)
- {
- PsppSheetViewColumn *column;
-
- column = make_data_column (data_sheet, i, base_width, incr_width);
- pspp_sheet_view_append_column (sheet_view, column);
- }
- make_new_variable_column (data_sheet, base_width, incr_width);
- }
-}
-
-enum
- {
- PROP_0,
- PROP_DATA_STORE,
- PROP_VALUE_LABELS,
- PROP_CASE_NUMBERS,
- PROP_CURRENT_CASE,
- PROP_MAY_CREATE_VARS,
- PROP_MAY_DELETE_VARS
- };
-
-static void
-psppire_data_sheet_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- PsppireDataSheet *obj = PSPPIRE_DATA_SHEET (object);
-
- switch (prop_id)
- {
- case PROP_DATA_STORE:
- psppire_data_sheet_set_data_store (
- obj, PSPPIRE_DATA_STORE (g_value_get_object (value)));
- break;
-
- case PROP_VALUE_LABELS:
- psppire_data_sheet_set_value_labels (obj, g_value_get_boolean (value));
- break;
-
- case PROP_CASE_NUMBERS:
- psppire_data_sheet_set_case_numbers (obj, g_value_get_boolean (value));
- break;
-
- case PROP_CURRENT_CASE:
- psppire_data_sheet_goto_case (obj, g_value_get_long (value));
- break;
-
- case PROP_MAY_CREATE_VARS:
- psppire_data_sheet_set_may_create_vars (obj,
- g_value_get_boolean (value));
- break;
-
- case PROP_MAY_DELETE_VARS:
- psppire_data_sheet_set_may_delete_vars (obj,
- g_value_get_boolean (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-psppire_data_sheet_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- PsppireDataSheet *obj = PSPPIRE_DATA_SHEET (object);
-
- switch (prop_id)
- {
- case PROP_DATA_STORE:
- g_value_set_object (value, psppire_data_sheet_get_data_store (obj));
- break;
-
- case PROP_VALUE_LABELS:
- g_value_set_boolean (value, psppire_data_sheet_get_value_labels (obj));
- break;
-
- case PROP_CASE_NUMBERS:
- g_value_set_boolean (value, psppire_data_sheet_get_case_numbers (obj));
- break;
-
- case PROP_CURRENT_CASE:
- g_value_set_long (value, psppire_data_sheet_get_selected_case (obj));
- break;
-
- case PROP_MAY_CREATE_VARS:
- g_value_set_boolean (value, obj->may_create_vars);
- break;
-
- case PROP_MAY_DELETE_VARS:
- g_value_set_boolean (value, obj->may_delete_vars);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-gboolean
-psppire_data_sheet_get_value_labels (const PsppireDataSheet *ds)
-{
- return ds->show_value_labels;
-}
-
-void
-psppire_data_sheet_set_value_labels (PsppireDataSheet *ds,
- gboolean show_value_labels)
-{
- show_value_labels = !!show_value_labels;
- if (show_value_labels != ds->show_value_labels)
- {
- ds->show_value_labels = show_value_labels;
- g_object_notify (G_OBJECT (ds), "value-labels");
-
- /* Pretend the model changed, to force the columns to be rebuilt.
- Otherwise cell renderers won't get changed from combo boxes to text
- entries or vice versa. */
- g_object_notify (G_OBJECT (ds), "model");
- }
-}
-
-gboolean
-psppire_data_sheet_get_case_numbers (const PsppireDataSheet *ds)
-{
- return ds->show_case_numbers;
-}
-
-void
-psppire_data_sheet_set_case_numbers (PsppireDataSheet *ds,
- gboolean show_case_numbers)
-{
- show_case_numbers = !!show_case_numbers;
- if (show_case_numbers != ds->show_case_numbers)
- {
- PsppSheetViewColumn *column;
-
- ds->show_case_numbers = show_case_numbers;
- column = pspp_sheet_view_get_column (PSPP_SHEET_VIEW (ds), 0);
- if (column)
- pspp_sheet_view_column_set_visible (column, show_case_numbers);
-
- g_object_notify (G_OBJECT (ds), "case-numbers");
- gtk_widget_queue_draw (GTK_WIDGET (ds));
- }
-}
-
-gboolean
-psppire_data_sheet_get_may_create_vars (PsppireDataSheet *data_sheet)
-{
- return data_sheet->may_create_vars;
-}
-
-void
-psppire_data_sheet_set_may_create_vars (PsppireDataSheet *data_sheet,
- gboolean may_create_vars)
-{
- if (data_sheet->may_create_vars != may_create_vars)
- {
- data_sheet->may_create_vars = may_create_vars;
- if (data_sheet->new_variable_column)
- pspp_sheet_view_column_set_visible (data_sheet->new_variable_column,
- may_create_vars);
-
- on_selection_changed (pspp_sheet_view_get_selection (
- PSPP_SHEET_VIEW (data_sheet)), NULL);
- }
-}
-
-gboolean
-psppire_data_sheet_get_may_delete_vars (PsppireDataSheet *data_sheet)
-{
- return data_sheet->may_delete_vars;
-}
-
-void
-psppire_data_sheet_set_may_delete_vars (PsppireDataSheet *data_sheet,
- gboolean may_delete_vars)
-{
- if (data_sheet->may_delete_vars != may_delete_vars)
- {
- data_sheet->may_delete_vars = may_delete_vars;
- on_selection_changed (pspp_sheet_view_get_selection (
- PSPP_SHEET_VIEW (data_sheet)), NULL);
- }
-}
-
-static PsppSheetViewColumn *
-psppire_data_sheet_find_column_for_variable (PsppireDataSheet *data_sheet,
- gint dict_index)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppireDataStore *data_store;
- PsppSheetViewColumn *column;
- struct variable *var;
- GList *list, *iter;
-
- data_store = psppire_data_sheet_get_data_store (data_sheet);
- g_return_val_if_fail (data_store != NULL, NULL);
- g_return_val_if_fail (data_store->dict != NULL, NULL);
-
- var = psppire_dict_get_variable (data_store->dict, dict_index);
- g_return_val_if_fail (var != NULL, NULL);
-
- column = NULL;
- list = pspp_sheet_view_get_columns (sheet_view);
- for (iter = list; iter != NULL; iter = iter->next)
- {
- PsppSheetViewColumn *c = iter->data;
- struct variable *v;
-
- v = g_object_get_data (G_OBJECT (c), "variable");
- if (v == var)
- {
- column = c;
- break;
- }
- }
- g_list_free (list);
-
- return column;
-}
-
-void
-psppire_data_sheet_goto_variable (PsppireDataSheet *data_sheet,
- gint dict_index)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppSheetViewColumn *column;
-
- column = psppire_data_sheet_find_column_for_variable (data_sheet,
- dict_index);
- if (column != NULL)
- {
- GtkTreePath *path;
-
- gint row = psppire_data_sheet_get_current_case (data_sheet);
- path = gtk_tree_path_new_from_indices (row >= 0 ? row : 0, -1);
-
- pspp_sheet_view_scroll_to_cell (sheet_view, path, column,
- FALSE, 0.0, 0.0);
- pspp_sheet_view_set_cursor (sheet_view, path, column, FALSE);
- gtk_tree_path_free (path);
- }
-}
-
-struct variable *
-psppire_data_sheet_get_current_variable (const PsppireDataSheet *data_sheet)
-{
- PsppSheetSelection *selection;
- struct variable *var;
- GList *selected_columns;
- GList *iter;
-
- selection = pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (data_sheet));
- selected_columns = pspp_sheet_selection_get_selected_columns (selection);
-
- var = NULL;
- for (iter = selected_columns; iter != NULL; iter = iter->next)
- {
- PsppSheetViewColumn *column = iter->data;
- struct variable *v = g_object_get_data (G_OBJECT (column), "variable");
- if (v != NULL)
- {
- if (var)
- {
- var = NULL;
- break;
- }
- else
- var = v;
- }
- }
-
- g_list_free (selected_columns);
-
- return var;
-
-}
-void
-psppire_data_sheet_goto_case (PsppireDataSheet *data_sheet, gint case_index)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppireDataStore *store = data_sheet->data_store;
- PsppSheetSelection *selection;
- GtkTreePath *path;
-
- g_return_if_fail (case_index >= 0);
- g_return_if_fail (case_index < psppire_data_store_get_case_count (store));
-
- path = gtk_tree_path_new_from_indices (case_index, -1);
-
- /* Select the case. */
- selection = pspp_sheet_view_get_selection (sheet_view);
- pspp_sheet_selection_unselect_all (selection);
- pspp_sheet_selection_select_path (selection, path);
- pspp_sheet_selection_select_all_columns (selection);
-
- /* Scroll so that the case is visible. */
- pspp_sheet_view_scroll_to_cell (sheet_view, path, NULL, FALSE, 0.0, 0.0);
-
- gtk_tree_path_free (path);
-}
-
-/* Returns the 0-based index of a selected case, if there is at least one, and
- -1 otherwise.
-
- If more than one case is selected, returns the one with the smallest index,
- that is, the index of the case closest to the beginning of the file. The
- row that can be used to insert a new case is not considered a case. */
-gint
-psppire_data_sheet_get_selected_case (const PsppireDataSheet *data_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppireDataStore *store = data_sheet->data_store;
- const struct range_set_node *node;
- PsppSheetSelection *selection;
- struct range_set *rows;
- gint row;
-
- selection = pspp_sheet_view_get_selection (sheet_view);
- rows = pspp_sheet_selection_get_range_set (selection);
- node = range_set_first (rows);
- row = (node && node->start < psppire_data_store_get_case_count (store)
- ? node->start
- : -1);
- range_set_destroy (rows);
-
- return row;
-}
-
-/* Returns the 0-based index of a selected case, if exactly one case is
- selected, and -1 otherwise. Returns -1 if the row that can be used to
- insert a new case is selected. */
-gint
-psppire_data_sheet_get_current_case (const PsppireDataSheet *data_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppireDataStore *store = data_sheet->data_store;
- const struct range_set_node *node;
- PsppSheetSelection *selection;
- struct range_set *rows;
- gint row;
-
- selection = pspp_sheet_view_get_selection (sheet_view);
- if (pspp_sheet_selection_count_selected_rows (selection) != 1)
- return -1;
-
- rows = pspp_sheet_selection_get_range_set (selection);
- node = range_set_first (rows);
- row = (node && node->start < psppire_data_store_get_case_count (store)
- ? node->start
- : -1);
- range_set_destroy (rows);
-
- return row;
-}
-
-
-static void
-psppire_data_sheet_dispose (GObject *object)
-{
- PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (object);
-
- if (data_sheet->clip != NULL && data_sheet->on_owner_change_signal != 0)
- {
- g_signal_handler_disconnect (data_sheet->clip,
- data_sheet->on_owner_change_signal);
- data_sheet->on_owner_change_signal = 0;
- }
-
- if (data_sheet->dispose_has_run)
- return;
-
- data_sheet->dispose_has_run = TRUE;
-
- psppire_data_sheet_unset_data_store (data_sheet);
-
- G_OBJECT_CLASS (psppire_data_sheet_parent_class)->dispose (object);
-}
-
-static void
-psppire_data_sheet_map (GtkWidget *widget)
-{
- PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (widget);
-
- GTK_WIDGET_CLASS (psppire_data_sheet_parent_class)->map (widget);
-
- data_sheet->clip = gtk_widget_get_clipboard (widget,
- GDK_SELECTION_CLIPBOARD);
- if (data_sheet->on_owner_change_signal)
- g_signal_handler_disconnect (data_sheet->clip,
- data_sheet->on_owner_change_signal);
- data_sheet->on_owner_change_signal
- = g_signal_connect (data_sheet->clip, "owner-change",
- G_CALLBACK (on_owner_change), widget);
- on_owner_change (data_sheet->clip, NULL, widget);
-}
-
-static void
-psppire_data_sheet_class_init (PsppireDataSheetClass *class)
-{
- GObjectClass *gobject_class;
- GtkWidgetClass *widget_class;
-
- gobject_class = G_OBJECT_CLASS (class);
- gobject_class->set_property = psppire_data_sheet_set_property;
- gobject_class->get_property = psppire_data_sheet_get_property;
- gobject_class->dispose = psppire_data_sheet_dispose;
-
- widget_class = GTK_WIDGET_CLASS (class);
- widget_class->map = psppire_data_sheet_map;
-
- g_signal_new ("var-double-clicked",
- G_OBJECT_CLASS_TYPE (gobject_class),
- G_SIGNAL_RUN_LAST,
- 0,
- g_signal_accumulator_true_handled, NULL,
- psppire_marshal_BOOLEAN__INT,
- G_TYPE_BOOLEAN, 1, G_TYPE_INT);
-
- g_object_class_install_property (
- gobject_class, PROP_DATA_STORE,
- g_param_spec_object ("data-store",
- "Data Store",
- "The data store for the data sheet to display.",
- PSPPIRE_TYPE_DATA_STORE,
- G_PARAM_WRITABLE | G_PARAM_READABLE));
-
- g_object_class_install_property (
- gobject_class, PROP_VALUE_LABELS,
- g_param_spec_boolean ("value-labels",
- "Value Labels",
- "Whether or not the data sheet should display labels instead of values",
- FALSE,
- G_PARAM_WRITABLE | G_PARAM_READABLE));
-
- g_object_class_install_property (
- gobject_class, PROP_CASE_NUMBERS,
- g_param_spec_boolean ("case-numbers",
- "Case Numbers",
- "Whether or not the data sheet should display case numbers",
- FALSE,
- G_PARAM_WRITABLE | G_PARAM_READABLE));
-
- g_object_class_install_property (
- gobject_class,
- PROP_CURRENT_CASE,
- g_param_spec_long ("current-case",
- "Current Case",
- "Zero based number of the selected case",
- 0, CASENUMBER_MAX,
- 0,
- G_PARAM_WRITABLE | G_PARAM_READABLE));
-
- g_object_class_install_property (
- gobject_class,
- PROP_MAY_CREATE_VARS,
- g_param_spec_boolean ("may-create-vars",
- "May create variables",
- "Whether the user may create more variables",
- TRUE,
- G_PARAM_READWRITE));
-
-
- g_object_class_install_property (
- gobject_class,
- PROP_MAY_DELETE_VARS,
- g_param_spec_boolean ("may-delete-vars",
- "May delete variables",
- "Whether the user may delete variables",
- TRUE,
- G_PARAM_READWRITE));
-}
-
-static void
-do_row_popup_menu (GtkWidget *widget, guint button, guint32 time)
-{
- PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (widget);
-
-
- gtk_menu_popup (GTK_MENU (data_sheet->row_popup_menu), NULL, NULL, NULL, NULL, button, time);
-}
-
-static void
-on_popup_menu (GtkWidget *widget, gpointer user_data UNUSED)
-{
- do_row_popup_menu (widget, 0, gtk_get_current_event_time ());
-}
-
-static gboolean
-on_button_pressed (GtkWidget *widget, GdkEventButton *event,
- gpointer user_data UNUSED)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (widget);
-
- if (event->type == GDK_BUTTON_PRESS && event->button == 3)
- {
- PsppSheetSelection *selection;
-
- selection = pspp_sheet_view_get_selection (sheet_view);
- if (pspp_sheet_selection_count_selected_rows (selection) <= 1)
- {
- GtkTreePath *path;
-
- if (pspp_sheet_view_get_path_at_pos (sheet_view, event->x, event->y,
- &path, NULL, NULL, NULL))
- {
- pspp_sheet_selection_unselect_all (selection);
- pspp_sheet_selection_select_path (selection, path);
- pspp_sheet_selection_select_all_columns (selection);
- gtk_tree_path_free (path);
- }
- }
-
- do_row_popup_menu (widget, event->button, event->time);
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-void
-psppire_data_sheet_edit_clear_cases (PsppireDataSheet *data_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
- const struct range_set_node *node;
- struct range_set *selected;
-
- selected = pspp_sheet_selection_get_range_set (selection);
- for (node = range_set_last (selected); node != NULL;
- node = range_set_prev (selected, node))
- {
- unsigned long int start = range_set_node_get_start (node);
- unsigned long int count = range_set_node_get_width (node);
-
- psppire_data_store_delete_cases (data_sheet->data_store, start, count);
- }
- range_set_destroy (selected);
-}
-
-static void
-on_selection_changed (PsppSheetSelection *selection,
- gpointer user_data UNUSED)
-{
- PsppSheetView *sheet_view = pspp_sheet_selection_get_tree_view (selection);
- PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (sheet_view);
- gboolean any_variables_selected;
- gboolean may_delete_cases, may_delete_vars, may_insert_vars;
- GList *list, *iter;
- GtkTreePath *path;
-
- GtkWidget *top = gtk_widget_get_toplevel (GTK_WIDGET (data_sheet));
- if (! PSPPIRE_IS_DATA_WINDOW (top))
- return;
-
- PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (top);
-
- gint n_selected_rows = pspp_sheet_selection_count_selected_rows (selection);
-
- gtk_widget_set_sensitive (dw->mi_insert_case, n_selected_rows > 0);
-
- switch (n_selected_rows)
- {
- case 0:
- may_delete_cases = FALSE;
- break;
-
- case 1:
- /* The row used for inserting new cases cannot be deleted. */
- path = gtk_tree_path_new_from_indices (
- psppire_data_store_get_case_count (data_sheet->data_store), -1);
- may_delete_cases = !pspp_sheet_selection_path_is_selected (selection,
- path);
- gtk_tree_path_free (path);
- break;
-
- default:
- may_delete_cases = TRUE;
- break;
- }
-
- gtk_widget_set_sensitive (dw->mi_clear_cases, may_delete_cases);
-
- any_variables_selected = FALSE;
- may_delete_vars = may_insert_vars = FALSE;
- list = pspp_sheet_selection_get_selected_columns (selection);
-
- for (iter = list; iter != NULL; iter = iter->next)
- {
- PsppSheetViewColumn *column = iter->data;
- struct variable *var = g_object_get_data (G_OBJECT (column), "variable");
-
- if (var != NULL)
- {
- may_delete_vars = may_insert_vars = TRUE;
- any_variables_selected = TRUE;
- break;
- }
- if (g_object_get_data (G_OBJECT (column), "new-var-column") != NULL)
- may_insert_vars = TRUE;
- }
- g_list_free (list);
-
- may_insert_vars = may_insert_vars && data_sheet->may_create_vars;
- may_delete_vars = may_delete_vars && data_sheet->may_delete_vars;
-
- gtk_widget_set_sensitive (dw->mi_insert_var, may_insert_vars);
- gtk_widget_set_sensitive (dw->mi_clear_variables, may_delete_vars);
- gtk_widget_set_sensitive (data_sheet->pu_sort_up, may_delete_vars);
- gtk_widget_set_sensitive (data_sheet->pu_sort_down, may_delete_vars);
-
- psppire_data_sheet_update_clip_actions (data_sheet);
- psppire_data_sheet_update_primary_selection (data_sheet,
- (n_selected_rows > 0
- && any_variables_selected));
-}
-
-static gboolean
-psppire_data_sheet_get_selected_range (PsppireDataSheet *data_sheet,
- struct range_set **rowsp,
- struct range_set **colsp)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppireDataStore *data_store = data_sheet->data_store;
- PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
- unsigned long n_cases;
- struct range_set *rows, *cols;
- GList *list, *iter;
-
- if (data_store == NULL)
- return FALSE;
- n_cases = psppire_data_store_get_case_count (data_store);
-
- rows = pspp_sheet_selection_get_range_set (selection);
- range_set_set0 (rows, n_cases, ULONG_MAX - n_cases);
- if (range_set_is_empty (rows))
- {
- range_set_destroy (rows);
- return FALSE;
- }
-
- cols = range_set_create ();
- list = pspp_sheet_selection_get_selected_columns (selection);
- for (iter = list; iter != NULL; iter = iter->next)
- {
- PsppSheetViewColumn *column = iter->data;
- struct variable *var = g_object_get_data (G_OBJECT (column), "variable");
-
- if (var != NULL)
- range_set_set1 (cols, var_get_dict_index (var), 1);
- }
- g_list_free (list);
- if (range_set_is_empty (cols))
- {
- range_set_destroy (rows);
- range_set_destroy (cols);
- return FALSE;
- }
-
- *rowsp = rows;
- *colsp = cols;
- return TRUE;
-}
-
-/* Insert a case at the selected row */
-void
-psppire_data_sheet_insert_case (PsppireDataSheet *data_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
- PsppireDataStore *data_store = data_sheet->data_store;
- struct range_set *selected = pspp_sheet_selection_get_range_set (selection);
- unsigned long row = range_set_scan (selected, 0);
- range_set_destroy (selected);
-
- if (row <= psppire_data_store_get_case_count (data_store))
- psppire_data_store_insert_new_case (data_store, row);
-}
-
-void
-psppire_data_sheet_insert_variable (PsppireDataSheet *data_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
- PsppireDict *dict = data_sheet->data_store->dict;
- PsppSheetViewColumn *column;
- struct variable *var;
- gchar name[64];
- GList *list;
- gint index;
-
- list = pspp_sheet_selection_get_selected_columns (selection);
- if (list == NULL)
- return;
- column = list->data;
- g_list_free (list);
-
- var = g_object_get_data (G_OBJECT (column), "variable");
- index = var ? var_get_dict_index (var) : psppire_dict_get_var_cnt (dict);
- if (psppire_dict_generate_name (dict, name, sizeof name))
- psppire_dict_insert_variable (dict, index, name);
-}
-
-void
-psppire_data_sheet_edit_clear_variables (PsppireDataSheet *data_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
- PsppireDict *dict = data_sheet->data_store->dict;
- GList *iter;
- GList *list = pspp_sheet_selection_get_selected_columns (selection);
-
- if (list == NULL)
- return;
- list = g_list_reverse (list);
- for (iter = list; iter; iter = iter->next)
- {
- PsppSheetViewColumn *column = iter->data;
- struct variable *var = g_object_get_data (G_OBJECT (column), "variable");
- if (var != NULL)
- psppire_dict_delete_variables (dict, var_get_dict_index (var), 1);
- }
- g_list_free (list);
-}
-
-void
-psppire_data_sheet_edit_copy (PsppireDataSheet *data_sheet)
-{
- psppire_data_sheet_set_clip (data_sheet, FALSE);
-}
-
-void
-psppire_data_sheet_edit_cut (PsppireDataSheet *data_sheet)
-{
- psppire_data_sheet_set_clip (data_sheet, TRUE);
-}
-
-void
-psppire_data_sheet_edit_paste (PsppireDataSheet *data_sheet)
-{
- GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (data_sheet));
- GtkClipboard *clipboard =
- gtk_clipboard_get_for_display (display, GDK_SELECTION_CLIPBOARD);
-
- gtk_clipboard_request_contents (clipboard,
- gdk_atom_intern ("UTF8_STRING", TRUE),
- psppire_data_sheet_clip_received_cb,
- data_sheet);
-}
-
-static void
-psppire_data_sheet_init (PsppireDataSheet *obj)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (obj);
-
- obj->show_value_labels = FALSE;
- obj->show_case_numbers = TRUE;
- obj->may_create_vars = TRUE;
- obj->may_delete_vars = TRUE;
-
- obj->owns_primary_selection = FALSE;
-
- obj->scroll_to_bottom_signal = 0;
- obj->scroll_to_right_signal = 0;
- obj->on_owner_change_signal = 0;
- obj->new_variable_column = NULL;
- obj->container = NULL;
-
- obj->dispose_has_run = FALSE;
-
- pspp_sheet_view_set_special_cells (sheet_view, PSPP_SHEET_VIEW_SPECIAL_CELLS_YES);
-
- {
- obj->row_popup_menu = gtk_menu_new ();
- int i = 0;
-
- GtkWidget *insert_case = gtk_menu_item_new_with_mnemonic (_("_Insert Case"));
- GtkWidget *clear_cases = gtk_menu_item_new_with_mnemonic (_("Cl_ear Cases"));
-
- gtk_menu_attach (GTK_MENU (obj->row_popup_menu), insert_case, 0, 1, i, i + 1); ++i;
- gtk_menu_attach (GTK_MENU (obj->row_popup_menu), clear_cases, 0, 1, i, i + 1); ++i;
-
- g_signal_connect_swapped (clear_cases, "activate", G_CALLBACK (psppire_data_sheet_edit_clear_cases), obj);
- g_signal_connect_swapped (insert_case, "activate", G_CALLBACK (psppire_data_sheet_insert_case), obj);
-
- gtk_widget_show_all (obj->row_popup_menu);
- }
-
- {
- obj->column_popup_menu = gtk_menu_new ();
- int i = 0;
-
- GtkWidget *insert_variable = gtk_menu_item_new_with_mnemonic (_("_Insert Variable"));
- GtkWidget *clear_variables = gtk_menu_item_new_with_mnemonic (_("Cl_ear Variables"));
- obj->pu_sort_up = gtk_menu_item_new_with_mnemonic (_("Sort _Ascending"));
- obj->pu_sort_down = gtk_menu_item_new_with_mnemonic (_("Sort _Descending"));
-
- g_signal_connect_swapped (clear_variables, "activate", G_CALLBACK (psppire_data_sheet_edit_clear_variables), obj);
- g_signal_connect_swapped (insert_variable, "activate", G_CALLBACK (psppire_data_sheet_insert_variable), obj);
-
- g_signal_connect_swapped (obj->pu_sort_up, "activate", G_CALLBACK (on_sort_up), obj);
- g_signal_connect_swapped (obj->pu_sort_down, "activate", G_CALLBACK (on_sort_down), obj);
-
- gtk_menu_attach (GTK_MENU (obj->column_popup_menu), insert_variable, 0, 1, i, i + 1); ++i;
- gtk_menu_attach (GTK_MENU (obj->column_popup_menu), clear_variables, 0, 1, i, i + 1); ++i;
-
- gtk_menu_attach (GTK_MENU (obj->column_popup_menu), gtk_separator_menu_item_new (), 0, 1, i, i + 1); ++i;
-
- gtk_menu_attach (GTK_MENU (obj->column_popup_menu), obj->pu_sort_up, 0, 1, i, i + 1); ++i;
- gtk_menu_attach (GTK_MENU (obj->column_popup_menu), obj->pu_sort_down, 0, 1, i, i + 1); ++i;
-
- gtk_widget_show_all (obj->column_popup_menu);
- }
-
-
- g_signal_connect (obj, "notify::model",
- G_CALLBACK (psppire_data_sheet_model_changed), NULL);
-
- pspp_sheet_view_set_rubber_banding (sheet_view, TRUE);
- pspp_sheet_selection_set_mode (pspp_sheet_view_get_selection (sheet_view),
- PSPP_SHEET_SELECTION_RECTANGLE);
-
- g_object_set (G_OBJECT (obj), "has-tooltip", TRUE, (void *) NULL);
- g_signal_connect (obj, "query-tooltip",
- G_CALLBACK (on_query_tooltip), NULL);
- g_signal_connect (obj, "button-press-event",
- G_CALLBACK (on_button_pressed), NULL);
-
- g_signal_connect (obj, "popup-menu", G_CALLBACK (on_popup_menu), NULL);
-
- g_signal_connect (pspp_sheet_view_get_selection (sheet_view),
- "changed", G_CALLBACK (on_selection_changed), NULL);
-}
-
-GtkWidget *
-psppire_data_sheet_new (void)
-{
- return g_object_new (PSPP_TYPE_DATA_SHEET, NULL);
-}
-
-PsppireDataStore *
-psppire_data_sheet_get_data_store (PsppireDataSheet *data_sheet)
-{
- return data_sheet->data_store;
-}
-
-static void
-refresh_model (PsppireDataSheet *data_sheet)
-{
- pspp_sheet_view_set_model (PSPP_SHEET_VIEW (data_sheet), NULL);
-
- if (data_sheet->data_store != NULL)
- {
- int n_rows = psppire_data_store_get_case_count (data_sheet->data_store) + 1;
- PsppireEmptyListStore *model = psppire_empty_list_store_new (n_rows);
- pspp_sheet_view_set_model (PSPP_SHEET_VIEW (data_sheet),
- GTK_TREE_MODEL (model));
- g_object_unref (model);
- }
-}
-
-static void
-on_case_inserted (PsppireDataStore *data_store, gint row,
- PsppireDataSheet *data_sheet)
-{
- PsppireEmptyListStore *empty_list_store;
- GtkTreeModel *tree_model;
- gint n_rows;
-
- g_return_if_fail (data_store == data_sheet->data_store);
-
- n_rows = psppire_data_store_get_case_count (data_store) + 1;
- if (row == n_rows - 1)
- row++;
-
- tree_model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (data_sheet));
- empty_list_store = PSPPIRE_EMPTY_LIST_STORE (tree_model);
- psppire_empty_list_store_set_n_rows (empty_list_store, n_rows);
- psppire_empty_list_store_row_inserted (empty_list_store, row);
-}
-
-static void
-on_cases_deleted (PsppireDataStore *data_store, gint first, gint n_cases,
- PsppireDataSheet *data_sheet)
-{
-
- g_return_if_fail (data_store == data_sheet->data_store);
-
- if (n_cases > 1)
- {
- /* This is a bit of a cop-out. We could do better, if it ever turns out
- that this performs too poorly. */
- refresh_model (data_sheet);
- }
- else
- {
- PsppireEmptyListStore *empty_list_store;
- GtkTreeModel *tree_model;
- gint n_rows = psppire_data_store_get_case_count (data_store) + 1;
-
- tree_model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (data_sheet));
- empty_list_store = PSPPIRE_EMPTY_LIST_STORE (tree_model);
- psppire_empty_list_store_set_n_rows (empty_list_store, n_rows);
- psppire_empty_list_store_row_deleted (empty_list_store, first);
- }
-}
-
-static void
-on_case_change (PsppireDataStore *data_store, gint row,
- PsppireDataSheet *data_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-
- pspp_sheet_view_stop_editing (sheet_view, TRUE);
- gtk_widget_queue_draw (GTK_WIDGET (data_sheet));
-}
-
-static void
-on_backend_changed (PsppireDataStore *data_store,
- PsppireDataSheet *data_sheet)
-{
- g_return_if_fail (data_store == data_sheet->data_store);
- refresh_model (data_sheet);
-}
-
-static void
-on_variable_display_width_changed (PsppireDict *dict, int dict_index,
- PsppireDataSheet *data_sheet)
-{
- PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
- PsppSheetViewColumn *column;
- struct variable *var;
- int display_width;
- gint pixel_width;
-
- g_return_if_fail (data_sheet->data_store != NULL);
- g_return_if_fail (dict == data_sheet->data_store->dict);
-
- column = psppire_data_sheet_find_column_for_variable (data_sheet,
- dict_index);
- if (column == NULL)
- return;
-
- var = psppire_dict_get_variable (data_store->dict, dict_index);
- g_return_if_fail (var != NULL);
-
- pixel_width = pspp_sheet_view_column_get_fixed_width (column);
- display_width = display_width_from_pixel_width (data_sheet, pixel_width);
- if (display_width != var_get_display_width (var))
- {
- gint base_width, incr_width;
-
- display_width = var_get_display_width (var);
- calc_width_conversion (data_sheet, &base_width, &incr_width);
- pixel_width = display_width_to_pixel_width (data_sheet, display_width,
- base_width, incr_width);
- pspp_sheet_view_column_set_fixed_width (column, pixel_width);
- }
-}
-
-static void
-on_variable_changed (PsppireDict *dict, int dict_index,
- guint what, const struct variable *oldvar,
- PsppireDataSheet *data_sheet)
-{
- PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
- PsppSheetViewColumn *column;
- GtkCellRenderer *cell;
- struct variable *var;
- GList *cells;
- char *name;
-
- g_return_if_fail (data_sheet->data_store != NULL);
- g_return_if_fail (dict == data_sheet->data_store->dict);
-
-
- if (what & VAR_TRAIT_DISPLAY_WIDTH)
- on_variable_display_width_changed (dict, dict_index, data_sheet);
-
- column = psppire_data_sheet_find_column_for_variable (data_sheet,
- dict_index);
- if (column == NULL)
- return;
-
-
- var = psppire_dict_get_variable (data_store->dict, dict_index);
- g_return_if_fail (var != NULL);
-
- name = escape_underscores (var_get_name (var));
- if (strcmp (name, pspp_sheet_view_column_get_title (column)))
- pspp_sheet_view_column_set_title (column, name);
- free (name);
-
- cells = pspp_sheet_view_column_get_cell_renderers (column);
- g_return_if_fail (cells);
- cell = cells->data;
- g_list_free (cells);
-
- if (var_has_value_labels (var) != GTK_IS_CELL_RENDERER_COMBO (cell))
- {
- /* Stop editing before we delete and replace the cell renderers.
- Otherwise if this column is currently being edited, an eventual call
- to pspp_sheet_view_stop_editing() will obtain a NULL cell and pass
- that to gtk_cell_renderer_stop_editing(), which causes a critical.
-
- It's possible that this is a bug in PsppSheetView, and it's possible
- that PsppSheetView inherits that from GtkTreeView, but I haven't
- investigated yet. */
- pspp_sheet_view_stop_editing (PSPP_SHEET_VIEW (data_sheet), TRUE);
-
- add_data_column_cell_renderer (data_sheet, column);
- }
-}
-
-static void
-on_variable_inserted (PsppireDict *dict, int var_index,
- PsppireDataSheet *data_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- gint base_width, incr_width;
- PsppSheetViewColumn *column;
-
- calc_width_conversion (data_sheet, &base_width, &incr_width);
- column = make_data_column (data_sheet, var_index, base_width, incr_width);
- pspp_sheet_view_insert_column (sheet_view, column, var_index + 1);
-}
-
-static void
-on_variable_deleted (PsppireDict *dict,
- const struct variable *var, int case_idx, int width,
- PsppireDataSheet *data_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- GList *columns, *iter;
-
- columns = pspp_sheet_view_get_columns (sheet_view);
- for (iter = columns; iter != NULL; iter = iter->next)
- {
- PsppSheetViewColumn *column = iter->data;
- const struct variable *column_var;
-
- column_var = g_object_get_data (G_OBJECT (column), "variable");
- if (column_var == var)
- pspp_sheet_view_remove_column (sheet_view, column);
- }
- g_list_free (columns);
-}
-
-static void
-psppire_data_sheet_unset_data_store (PsppireDataSheet *data_sheet)
-{
- PsppireDataStore *store = data_sheet->data_store;
-
- if (store == NULL)
- return;
-
- data_sheet->data_store = NULL;
-
- g_signal_handlers_disconnect_by_func (
- store, G_CALLBACK (on_backend_changed), data_sheet);
- g_signal_handlers_disconnect_by_func (
- store, G_CALLBACK (on_case_inserted), data_sheet);
- g_signal_handlers_disconnect_by_func (
- store, G_CALLBACK (on_cases_deleted), data_sheet);
- g_signal_handlers_disconnect_by_func (
- store, G_CALLBACK (on_case_change), data_sheet);
-
- g_signal_handlers_disconnect_by_func (
- store->dict, G_CALLBACK (on_variable_changed), data_sheet);
- g_signal_handlers_disconnect_by_func (
- store->dict, G_CALLBACK (on_variable_display_width_changed), data_sheet);
- g_signal_handlers_disconnect_by_func (
- store->dict, G_CALLBACK (on_variable_inserted), data_sheet);
- g_signal_handlers_disconnect_by_func (
- store->dict, G_CALLBACK (on_variable_deleted), data_sheet);
-
- g_object_unref (store);
-}
-
-void
-psppire_data_sheet_set_data_store (PsppireDataSheet *data_sheet,
- PsppireDataStore *data_store)
-{
- psppire_data_sheet_unset_data_store (data_sheet);
-
- data_sheet->data_store = data_store;
- if (data_store != NULL)
- {
- g_object_ref (data_store);
- g_signal_connect (data_store, "backend-changed",
- G_CALLBACK (on_backend_changed), data_sheet);
- g_signal_connect (data_store, "case-inserted",
- G_CALLBACK (on_case_inserted), data_sheet);
- g_signal_connect (data_store, "cases-deleted",
- G_CALLBACK (on_cases_deleted), data_sheet);
- g_signal_connect (data_store, "case-changed",
- G_CALLBACK (on_case_change), data_sheet);
-
- /* XXX it's unclean to hook into the dict this way--what if the dict
- changes? As of this writing, though, nothing ever changes the
- data_store's dict. */
- g_signal_connect (data_store->dict, "variable-changed",
- G_CALLBACK (on_variable_changed),
- data_sheet);
- g_signal_connect (data_store->dict, "variable-inserted",
- G_CALLBACK (on_variable_inserted), data_sheet);
- g_signal_connect (data_store->dict, "variable-deleted",
- G_CALLBACK (on_variable_deleted), data_sheet);
- }
- refresh_model (data_sheet);
-}
-\f
-/* Clipboard stuff */
-
-/* A casereader and dictionary holding the data currently in the clip */
-static struct casereader *clip_datasheet = NULL;
-static struct dictionary *clip_dict = NULL;
-
-
-static void psppire_data_sheet_update_clipboard (PsppireDataSheet *);
-
-static gboolean
-psppire_data_sheet_fetch_clip (PsppireDataSheet *data_sheet, gboolean cut,
- struct casereader **readerp,
- struct dictionary **dictp)
-{
- struct casewriter *writer ;
- PsppireDataStore *ds = psppire_data_sheet_get_data_store (data_sheet);
- struct case_map *map = NULL;
- struct range_set *rows, *cols;
- const struct range_set_node *node;
- struct dictionary *dict;
-
- if (!psppire_data_sheet_get_selected_range (data_sheet, &rows, &cols))
- {
- *readerp = NULL;
- *dictp = NULL;
- return FALSE;
- }
-
- /* Construct clip dictionary. */
- *dictp = dict = dict_create (dict_get_encoding (ds->dict->dict));
- RANGE_SET_FOR_EACH (node, cols)
- {
- int dict_index;
-
- for (dict_index = node->start; dict_index < node->end; dict_index++)
- {
- struct variable *var = dict_get_var (ds->dict->dict, dict_index);
- dict_clone_var_assert (dict, var);
- }
- }
-
- /* Construct clip data. */
- map = case_map_by_name (ds->dict->dict, dict);
- writer = autopaging_writer_create (dict_get_proto (dict));
- RANGE_SET_FOR_EACH (node, rows)
- {
- unsigned long int row;
-
- for (row = node->start; row < node->end; row++)
- {
- struct ccase *old = psppire_data_store_get_case (ds, row);
- if (old != NULL)
- casewriter_write (writer, case_map_execute (map, old));
- else
- casewriter_force_error (writer);
- }
- }
- case_map_destroy (map);
-
- /* Clear data that we copied out, if we're doing a "cut". */
- if (cut && !casewriter_error (writer))
- {
- RANGE_SET_FOR_EACH (node, rows)
- {
- unsigned long int row;
-
- for (row = node->start; row < node->end; row++)
- {
- const struct range_set_node *node2;
-
- RANGE_SET_FOR_EACH (node2, cols)
- {
- int dict_index;
-
- for (dict_index = node2->start; dict_index < node2->end;
- dict_index++)
- {
- struct variable *var;
-
- var = dict_get_var (ds->dict->dict, dict_index);
- psppire_data_store_set_string (ds, "", row,
- var, false);
- }
- }
- }
- }
- }
-
- range_set_destroy (rows);
- range_set_destroy (cols);
-
- *readerp = casewriter_make_reader (writer);
-
- return TRUE;
-}
-
-/* Set the clip from the currently selected range in DATA_SHEET. If CUT is
- true, clears the original data from DATA_SHEET, otherwise leaves the
- original data in-place. */
-static void
-psppire_data_sheet_set_clip (PsppireDataSheet *data_sheet,
- gboolean cut)
-{
- struct casereader *reader;
- struct dictionary *dict;
-
- if (psppire_data_sheet_fetch_clip (data_sheet, cut, &reader, &dict))
- {
- casereader_destroy (clip_datasheet);
- dict_destroy (clip_dict);
-
- clip_datasheet = reader;
- clip_dict = dict;
-
- psppire_data_sheet_update_clipboard (data_sheet);
- }
-}
-
-enum {
- SELECT_FMT_NULL,
- SELECT_FMT_TEXT,
- SELECT_FMT_HTML
-};
-
-
-/* Perform data_out for case CC, variable V, appending to STRING */
-static void
-data_out_g_string (GString *string, const struct variable *v,
- const struct ccase *cc)
-{
- const struct fmt_spec *fs = var_get_print_format (v);
- const union value *val = case_data (cc, v);
-
- char *s = data_out (val, var_get_encoding (v), fs);
-
- g_string_append (string, s);
-
- g_free (s);
-}
-
-static GString *
-clip_to_text (struct casereader *datasheet, struct dictionary *dict)
-{
- casenumber r;
- GString *string;
-
- const size_t val_cnt = caseproto_get_n_widths (casereader_get_proto (datasheet));
- const casenumber case_cnt = casereader_get_case_cnt (datasheet);
- const size_t var_cnt = dict_get_var_cnt (dict);
-
- string = g_string_sized_new (10 * val_cnt * case_cnt);
-
- for (r = 0 ; r < case_cnt ; ++r )
- {
- int c;
- struct ccase *cc;
-
- cc = casereader_peek (datasheet, r);
- if (cc == NULL)
- {
- g_warning ("Clipboard seems to have inexplicably shrunk");
- break;
- }
-
- for (c = 0 ; c < var_cnt ; ++c)
- {
- const struct variable *v = dict_get_var (dict, c);
- data_out_g_string (string, v, cc);
- if ( c < val_cnt - 1 )
- g_string_append (string, "\t");
- }
-
- if ( r < case_cnt)
- g_string_append (string, "\n");
-
- case_unref (cc);
- }
-
- return string;
-}
-
-
-static GString *
-clip_to_html (struct casereader *datasheet, struct dictionary *dict)
-{
- casenumber r;
- GString *string;
-
- const size_t val_cnt = caseproto_get_n_widths (casereader_get_proto (datasheet));
- const casenumber case_cnt = casereader_get_case_cnt (datasheet);
- const size_t var_cnt = dict_get_var_cnt (dict);
-
- /* Guestimate the size needed */
- string = g_string_sized_new (80 + 20 * val_cnt * case_cnt);
-
- g_string_append (string,
- "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n");
-
- g_string_append (string, "<table>\n");
- for (r = 0 ; r < case_cnt ; ++r )
- {
- int c;
- struct ccase *cc = casereader_peek (datasheet, r);
- if (cc == NULL)
- {
- g_warning ("Clipboard seems to have inexplicably shrunk");
- break;
- }
- g_string_append (string, "<tr>\n");
-
- for (c = 0 ; c < var_cnt ; ++c)
- {
- const struct variable *v = dict_get_var (dict, c);
- g_string_append (string, "<td>");
- data_out_g_string (string, v, cc);
- g_string_append (string, "</td>\n");
- }
-
- g_string_append (string, "</tr>\n");
-
- case_unref (cc);
- }
- g_string_append (string, "</table>\n");
-
- return string;
-}
-
-
-
-static void
-psppire_data_sheet_clipboard_set (GtkSelectionData *selection_data,
- guint info,
- struct casereader *reader,
- struct dictionary *dict)
-{
- GString *string = NULL;
-
- switch (info)
- {
- case SELECT_FMT_TEXT:
- string = clip_to_text (reader, dict);
- break;
- case SELECT_FMT_HTML:
- string = clip_to_html (reader, dict);
- break;
- default:
- g_assert_not_reached ();
- }
-
- gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data),
- 8,
- (const guchar *) string->str, string->len);
-
- g_string_free (string, TRUE);
-}
-
-static void
-psppire_data_sheet_clipboard_get_cb (GtkClipboard *clipboard,
- GtkSelectionData *selection_data,
- guint info,
- gpointer data)
-{
- psppire_data_sheet_clipboard_set (selection_data, info,
- clip_datasheet, clip_dict);
-}
-
-static void
-psppire_data_sheet_clipboard_clear_cb (GtkClipboard *clipboard,
- gpointer data)
-{
- dict_destroy (clip_dict);
- clip_dict = NULL;
-
- casereader_destroy (clip_datasheet);
- clip_datasheet = NULL;
-}
-
-
-static const GtkTargetEntry targets[] = {
- { "UTF8_STRING", 0, SELECT_FMT_TEXT },
- { "STRING", 0, SELECT_FMT_TEXT },
- { "TEXT", 0, SELECT_FMT_TEXT },
- { "COMPOUND_TEXT", 0, SELECT_FMT_TEXT },
- { "text/plain;charset=utf-8", 0, SELECT_FMT_TEXT },
- { "text/plain", 0, SELECT_FMT_TEXT },
- { "text/html", 0, SELECT_FMT_HTML }
-};
-
-
-
-static void
-psppire_data_sheet_update_clipboard (PsppireDataSheet *sheet)
-{
- GtkClipboard *clipboard =
- gtk_widget_get_clipboard (GTK_WIDGET (sheet),
- GDK_SELECTION_CLIPBOARD);
-
- if (!gtk_clipboard_set_with_owner (clipboard, targets,
- G_N_ELEMENTS (targets),
- psppire_data_sheet_clipboard_get_cb,
- psppire_data_sheet_clipboard_clear_cb,
- G_OBJECT (sheet)))
- psppire_data_sheet_clipboard_clear_cb (clipboard, sheet);
-}
-
-static void
-psppire_data_sheet_update_clip_actions (PsppireDataSheet *data_sheet)
-{
- struct range_set *rows, *cols;
- GtkWidget *top = gtk_widget_get_toplevel (GTK_WIDGET (data_sheet));
- if (! PSPPIRE_IS_DATA_WINDOW (top))
- return;
-
- PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (top);
- gboolean enable =
- psppire_data_sheet_get_selected_range (data_sheet, &rows, &cols);
-
- if (enable)
- {
- range_set_destroy (rows);
- range_set_destroy (cols);
- }
-
- gtk_widget_set_sensitive (dw->mi_copy, enable);
- gtk_widget_set_sensitive (dw->mi_cut, enable);
-}
-
-static void
-psppire_data_sheet_primary_get_cb (GtkClipboard *clipboard,
- GtkSelectionData *selection_data,
- guint info,
- gpointer data)
-{
- PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (data);
- struct casereader *reader;
- struct dictionary *dict;
-
- if (psppire_data_sheet_fetch_clip (data_sheet, FALSE, &reader, &dict))
- {
- psppire_data_sheet_clipboard_set (selection_data, info,
- reader, dict);
- casereader_destroy (reader);
- dict_destroy (dict);
- }
-}
-
-static void
-psppire_data_sheet_update_primary_selection (PsppireDataSheet *data_sheet,
- gboolean should_own)
-{
- GtkClipboard *clipboard;
- GdkDisplay *display;
-
- display = gtk_widget_get_display (GTK_WIDGET (data_sheet));
- clipboard = gtk_clipboard_get_for_display (display, GDK_SELECTION_PRIMARY);
- g_return_if_fail (clipboard != NULL);
-
- if (data_sheet->owns_primary_selection && !should_own)
- {
- data_sheet->owns_primary_selection = FALSE;
- gtk_clipboard_clear (clipboard);
- }
- else if (should_own)
- data_sheet->owns_primary_selection =
- gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
- psppire_data_sheet_primary_get_cb,
- NULL, G_OBJECT (data_sheet));
-}
-\f
-/* A callback for when the clipboard contents have been received. */
-static void
-psppire_data_sheet_clip_received_cb (GtkClipboard *clipboard,
- GtkSelectionData *sd,
- gpointer data)
-{
- PsppireDataSheet *data_sheet = data;
- PsppireDataStore *store = data_sheet->data_store;
- struct range_set *rows, *cols;
- gint count = 0;
- gint next_row, next_column;
- gint first_column;
- char *c;
-
- if ( gtk_selection_data_get_length (sd) < 0 )
- return;
-
- if ( gtk_selection_data_get_data_type (sd) != gdk_atom_intern ("UTF8_STRING", FALSE))
- return;
-
- c = (char *) gtk_selection_data_get_data (sd);
-
- /* Get the starting selected position in the data sheet. (Possibly we should
- only paste into the selected range if it's larger than one cell?) */
- if (!psppire_data_sheet_get_selected_range (data_sheet, &rows, &cols))
- return;
- next_row = range_set_first (rows)->start;
- first_column = next_column = range_set_first (cols)->start;
- range_set_destroy (rows);
- range_set_destroy (cols);
-
- g_return_if_fail (next_row >= 0);
- g_return_if_fail (next_column >= 0);
-
- while (count < gtk_selection_data_get_length (sd))
- {
- gint row = next_row;
- gint column = next_column;
- struct variable *var;
- char *s = c;
-
- while (*c != '\t' && *c != '\n' && count < gtk_selection_data_get_length (sd))
- {
- c++;
- count++;
- }
- if ( *c == '\t')
- {
- next_row = row ;
- next_column = column + 1;
- }
- else if ( *c == '\n')
- {
- next_row = row + 1;
- next_column = first_column;
- }
- *c++ = '\0';
- count++;
-
- var = psppire_dict_get_variable (store->dict, column);
- if (var != NULL)
- psppire_data_store_set_string (store, s, row, var, FALSE);
- }
-}
-
-static void
-psppire_data_sheet_targets_received_cb (GtkClipboard *clipboard,
- GdkAtom *atoms,
- gint n_atoms,
- gpointer data)
-{
- GtkWidget *mi = GTK_WIDGET (data);
- gboolean compatible_target = FALSE;
- gint i;
- for (i = 0; i < G_N_ELEMENTS (targets); i++)
- {
- GdkAtom target = gdk_atom_intern (targets[i].target, TRUE);
- gint j;
-
- for (j = 0; j < n_atoms; j++)
- if (target == atoms[j])
- {
- compatible_target = TRUE;
- break;
- }
- }
-
- gtk_widget_set_sensitive (mi, compatible_target);
-}
-
-static void
-on_owner_change (GtkClipboard *clip, GdkEventOwnerChange *event, gpointer data)
-{
- PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (data);
-
- GtkWidget *top = gtk_widget_get_toplevel (GTK_WIDGET (data_sheet));
- if (! PSPPIRE_IS_DATA_WINDOW (top))
- return;
-
- PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (top);
-
- gtk_clipboard_request_targets (clip,
- psppire_data_sheet_targets_received_cb,
- dw->mi_paste);
-}
+++ /dev/null
-/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2011, 2012, 2013 Free Software Foundation, Inc.
-
- 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/>. */
-
-#ifndef PSPPIRE_DATA_SHEET_H
-#define PSPPIRE_DATA_SHEET_H 1
-
-/* PsppireDataSheet is a PsppSheetView that displays the data in a dataset,
- with one column per variable and one row per case.
-
- PsppireDataSheet is usually a child of PsppireDataEditor in the widget
- hierarchy. Other widgets can also use it. */
-
-#include <gtk/gtk.h>
-#include "ui/gui/pspp-sheet-view.h"
-
-G_BEGIN_DECLS
-
-#define PSPP_TYPE_DATA_SHEET (psppire_data_sheet_get_type())
-#define PSPPIRE_DATA_SHEET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),PSPP_TYPE_DATA_SHEET,PsppireDataSheet))
-#define PSPPIRE_DATA_SHEET_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class),PSPP_TYPE_DATA_SHEET,PsppireDataSheetClass))
-#define PSPP_IS_DATA_SHEET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),PSPP_TYPE_DATA_SHEET))
-#define PSPP_IS_DATA_SHEET_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class),PSPP_TYPE_DATA_SHEET))
-#define PSPPIRE_DATA_SHEET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),PSPP_TYPE_DATA_SHEET,PsppireDataSheetClass))
-
-typedef struct _PsppireDataSheet PsppireDataSheet;
-typedef struct _PsppireDataSheetClass PsppireDataSheetClass;
-
-struct _PsppireDataSheet
-{
- PsppSheetView parent;
-
- struct _PsppireDataStore *data_store;
- gboolean show_value_labels;
- gboolean show_case_numbers;
- gboolean may_create_vars;
- gboolean may_delete_vars;
-
- gboolean owns_primary_selection;
-
- guint scroll_to_bottom_signal;
- guint scroll_to_right_signal;
-
- GtkClipboard *clip;
- guint on_owner_change_signal;
-
- PsppSheetViewColumn *new_variable_column;
-
- GtkWidget *container;
- gboolean dispose_has_run;
-
- GtkWidget *column_popup_menu;
- GtkWidget *row_popup_menu;
-
- GtkWidget *pu_sort_up;
- GtkWidget *pu_sort_down;
-};
-
-struct _PsppireDataSheetClass
-{
- PsppSheetViewClass parent_class;
-};
-
-GType psppire_data_sheet_get_type (void) G_GNUC_CONST;
-GtkWidget *psppire_data_sheet_new (void);
-
-struct _PsppireDataStore *psppire_data_sheet_get_data_store (PsppireDataSheet *);
-void psppire_data_sheet_set_data_store (PsppireDataSheet *,
- struct _PsppireDataStore *);
-
-gboolean psppire_data_sheet_get_value_labels (const PsppireDataSheet *);
-void psppire_data_sheet_set_value_labels (PsppireDataSheet *,
- gboolean show_value_labels);
-
-gboolean psppire_data_sheet_get_case_numbers (const PsppireDataSheet *);
-void psppire_data_sheet_set_case_numbers (PsppireDataSheet *,
- gboolean show_case_numbers);
-
-gboolean psppire_data_sheet_get_may_create_vars (PsppireDataSheet *);
-void psppire_data_sheet_set_may_create_vars (PsppireDataSheet *, gboolean);
-
-gboolean psppire_data_sheet_get_may_delete_vars (PsppireDataSheet *);
-void psppire_data_sheet_set_may_delete_vars (PsppireDataSheet *, gboolean);
-
-void psppire_data_sheet_goto_variable (PsppireDataSheet *, gint dict_index);
-struct variable *psppire_data_sheet_get_current_variable (const PsppireDataSheet *);
-
-void psppire_data_sheet_goto_case (PsppireDataSheet *, gint case_index);
-gint psppire_data_sheet_get_selected_case (const PsppireDataSheet *);
-gint psppire_data_sheet_get_current_case (const PsppireDataSheet *);
-
-void psppire_data_sheet_insert_case (PsppireDataSheet *data_sheet);
-void psppire_data_sheet_insert_variable (PsppireDataSheet *data_sheet);
-
-void psppire_data_sheet_edit_cut (PsppireDataSheet *data_sheet);
-void psppire_data_sheet_edit_copy (PsppireDataSheet *data_sheet);
-void psppire_data_sheet_edit_paste (PsppireDataSheet *data_sheet);
-
-void psppire_data_sheet_edit_clear_cases (PsppireDataSheet *data_sheet);
-void psppire_data_sheet_edit_clear_variables (PsppireDataSheet *data_sheet);
-
-G_END_DECLS
-
-#endif /* PSPPIRE_DATA_SHEET_H */
#include "xalloc.h"
#include "xmalloca.h"
-
+#include "value-variant.h"
static void psppire_data_store_init (PsppireDataStore *data_store);
static void psppire_data_store_class_init (PsppireDataStoreClass *class);
enum
{
- BACKEND_CHANGED,
+ ITEMS_CHANGED,
CASES_DELETED,
CASE_INSERTED,
CASE_CHANGED,
static guint signals [n_SIGNALS];
+static gint
+__tree_model_iter_n_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ PsppireDataStore *store = PSPPIRE_DATA_STORE (tree_model);
+
+ gint n = datasheet_get_n_rows (store->datasheet);
+
+ return n;
+}
+
+static GtkTreeModelFlags
+__tree_model_get_flags (GtkTreeModel *model)
+{
+ g_return_val_if_fail (PSPPIRE_IS_DATA_STORE (model), (GtkTreeModelFlags) 0);
+
+ return GTK_TREE_MODEL_LIST_ONLY;
+}
+
+static gint
+__tree_model_get_n_columns (GtkTreeModel *tree_model)
+{
+ PsppireDataStore *store = PSPPIRE_DATA_STORE (tree_model);
+
+ return psppire_dict_get_value_cnt (store->dict);
+}
+
+
+static gboolean
+__iter_nth_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ gint n)
+{
+ PsppireDataStore *store = PSPPIRE_DATA_STORE (tree_model);
+
+ g_assert (parent == NULL);
+
+ g_return_val_if_fail (store, FALSE);
+ g_return_val_if_fail (store->datasheet, FALSE);
+
+ if (n >= datasheet_get_n_rows (store->datasheet))
+ {
+ iter->stamp = -1;
+ iter->user_data = NULL;
+ return FALSE;
+ }
+
+ iter->user_data = GINT_TO_POINTER (n);
+ iter->stamp = store->stamp;
+
+ return TRUE;
+}
+
+void
+myreversefunc (GtkTreeModel *model, gint col, gint row,
+ const gchar *in, GValue *out)
+{
+ PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
+
+ const struct variable *variable = psppire_dict_get_variable (store->dict, col);
+ g_return_if_fail (variable);
+
+ const struct fmt_spec *fmt = var_get_print_format (variable);
+
+ int width = var_get_width (variable);
+
+ union value val;
+ value_init (&val, width);
+ char *xx =
+ data_in (ss_cstr (in), psppire_dict_encoding (store->dict),
+ fmt->type, &val, width, "UTF-8");
+
+ GVariant *vrnt = value_variant_new (&val, width);
+ value_destroy (&val, width);
+
+ g_value_init (out, G_TYPE_VARIANT);
+ g_value_set_variant (out, vrnt);
+ free (xx);
+}
+
+gchar *
+myconvfunc (GtkTreeModel *model, gint col, gint row, const GValue *v)
+{
+ PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
+
+ const struct variable *variable = psppire_dict_get_variable (store->dict, col);
+ g_return_val_if_fail (variable, g_strdup ("???"));
+
+ GVariant *vrnt = g_value_get_variant (v);
+ union value val;
+ value_variant_get (&val, vrnt);
+
+ const struct fmt_spec *fmt = var_get_print_format (variable);
+ char *out = data_out (&val, psppire_dict_encoding (store->dict), fmt);
+ value_destroy_from_variant (&val, vrnt);
+
+ return out;
+}
+
+static void
+__get_value (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gint column,
+ GValue *value)
+{
+ PsppireDataStore *store = PSPPIRE_DATA_STORE (tree_model);
+
+ g_return_if_fail (iter->stamp == store->stamp);
+
+ const struct variable *variable = psppire_dict_get_variable (store->dict, column);
+ if (NULL == variable)
+ return;
+
+ g_value_init (value, G_TYPE_VARIANT);
+
+ gint row = GPOINTER_TO_INT (iter->user_data);
+
+ struct ccase *cc = datasheet_get_row (store->datasheet, row);
+
+ const union value *val = case_data_idx (cc, column);
+
+ GVariant *vv = value_variant_new (val, var_get_width (variable));
+
+ g_value_set_variant (value, vv);
+
+ case_unref (cc);
+}
+
+
+static void
+__tree_model_init (GtkTreeModelIface *iface)
+{
+ iface->get_flags = __tree_model_get_flags;
+ iface->get_n_columns = __tree_model_get_n_columns ;
+ iface->get_column_type = NULL;
+ iface->get_iter = NULL;
+ iface->iter_next = NULL;
+ iface->get_path = NULL;
+ iface->get_value = __get_value;
+
+ iface->iter_children = NULL;
+ iface->iter_has_child = NULL;
+ iface->iter_n_children = __tree_model_iter_n_children;
+ iface->iter_nth_child = __iter_nth_child;
+ iface->iter_parent = NULL;
+}
+
GType
psppire_data_store_get_type (void)
(GInstanceInitFunc) psppire_data_store_init,
};
+ static const GInterfaceInfo tree_model_info = {
+ (GInterfaceInitFunc) __tree_model_init,
+ NULL,
+ NULL
+ };
+
data_store_type = g_type_register_static (G_TYPE_OBJECT,
"PsppireDataStore",
&data_store_info, 0);
+
+ g_type_add_interface_static (data_store_type, GTK_TYPE_TREE_MODEL,
+ &tree_model_info);
}
return data_store_type;
object_class->finalize = psppire_data_store_finalize;
object_class->dispose = psppire_data_store_dispose;
- signals [BACKEND_CHANGED] =
- g_signal_new ("backend-changed",
+ signals [ITEMS_CHANGED] =
+ g_signal_new ("changed",
G_TYPE_FROM_CLASS (class),
G_SIGNAL_RUN_FIRST,
0,
NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
+ psppire_marshal_VOID__UINT_UINT_UINT,
G_TYPE_NONE,
- 0);
+ 3,
+ G_TYPE_UINT,
+ G_TYPE_UINT,
+ G_TYPE_UINT);
signals [CASE_INSERTED] =
g_signal_new ("case-inserted",
data_store->dict = NULL;
data_store->datasheet = NULL;
data_store->dispose_has_run = FALSE;
+ data_store->stamp = g_random_int ();
}
/*
struct casereader *reader)
{
gint i;
-
+ gint old_n = 0;
if ( ds->datasheet)
- datasheet_destroy (ds->datasheet);
+ {
+ old_n = datasheet_get_n_rows (ds->datasheet);
+ datasheet_destroy (ds->datasheet);
+ }
ds->datasheet = datasheet_create (reader);
+ gint new_n = datasheet_get_n_rows (ds->datasheet);
+
if ( ds->dict )
for (i = 0 ; i < n_dict_signals; ++i )
{
}
}
- g_signal_emit (ds, signals[BACKEND_CHANGED], 0);
+ g_signal_emit (ds, signals[ITEMS_CHANGED], 0, 0, old_n, new_n);
}
return result;
}
-gchar *
-psppire_data_store_get_string (PsppireDataStore *store,
- glong row, const struct variable *var,
- bool use_value_label)
+gboolean
+psppire_data_store_get_value (PsppireDataStore *store,
+ glong row, const struct variable *var,
+ union value *val)
{
- gchar *string;
- union value v;
- int width;
-
g_return_val_if_fail (store != NULL, NULL);
g_return_val_if_fail (store->datasheet != NULL, NULL);
g_return_val_if_fail (var != NULL, NULL);
if (row < 0 || row >= datasheet_get_n_rows (store->datasheet))
- return NULL;
+ return FALSE;
- width = var_get_width (var);
- value_init (&v, width);
- datasheet_get_value (store->datasheet, row, var_get_case_index (var), &v);
+ int width = var_get_width (var);
+ value_init (val, width);
+ datasheet_get_value (store->datasheet, row, var_get_case_index (var), val);
+ return TRUE;
+}
+
+
+
+gchar *
+psppire_data_store_get_string (PsppireDataStore *store,
+ glong row, const struct variable *var,
+ bool use_value_label)
+{
+ gchar *string;
+ union value v;
+ int width = var_get_width (var);
+ if (! psppire_data_store_get_value (store, row, var, &v))
+ return NULL;
+
string = NULL;
if (use_value_label)
{
gboolean dispose_has_run ;
PsppireDict *dict;
struct datasheet *datasheet;
+ gint stamp;
gint dict_handler_id [n_dict_signals];
};
gchar *psppire_data_store_get_string (PsppireDataStore *,
glong row, const struct variable *,
bool use_value_label);
+
+
+gboolean psppire_data_store_get_value (PsppireDataStore *store,
+ glong row, const struct variable *var,
+ union value *val);
+
gboolean psppire_data_store_set_value (PsppireDataStore *,
casenumber casenum,
const struct variable *,
const union value *);
+
+
gboolean psppire_data_store_set_string (PsppireDataStore *ds,
const gchar *text,
glong row, const struct variable *,
#include "ui/gui/psppire-encoding-selector.h"
#include "ui/gui/psppire-syntax-window.h"
#include "ui/gui/psppire-window.h"
-#include "ui/gui/psppire-data-sheet.h"
-#include "ui/gui/psppire-var-sheet.h"
#include "ui/gui/windows-menu.h"
#include "ui/gui/goto-case-dialog.h"
#include "ui/gui/psppire.h"
#include "gl/c-strcasestr.h"
#include "gl/xvasprintf.h"
+#include "ui/gui/efficient-sheet/jmd-sheet.h"
+
#include "find-dialog.h"
#include "psppire-dialog-action-1sks.h"
#include "psppire-dialog-action-aggregate.h"
int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
if (p == 0)
{
- PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
- psppire_data_sheet_edit_cut (ds);
+ PsppireDict *dict = NULL;
+ g_object_get (dw->data_editor, "dictionary", &dict, NULL);
+
+ gint x, y;
+ JmdSheet *sheet = JMD_SHEET (dw->data_editor->data_sheet);
+ JmdRange sel = *sheet->selection;
+
+ GtkClipboard *clip =
+ gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
+ GDK_SELECTION_CLIPBOARD);
+
+ /* Save the selected area to a string */
+ GString *str = g_string_new ("");
+ for (y = sel.start_y ; y <= sel.end_y; ++y)
+ {
+ for (x = sel.start_x ; x <= sel.end_x; ++x)
+ {
+ const struct variable * var = psppire_dict_get_variable (dict, x);
+ gchar *s = psppire_data_store_get_string (dw->data_editor->data_store,
+ y, var, FALSE);
+ g_string_append (str, s);
+ g_string_append (str, "\t");
+ g_free (s);
+ }
+ g_string_append (str, "\n");
+ }
+
+ gtk_clipboard_set_text (clip, str->str, str->len);
+ g_string_free (str, TRUE);
+
+ /* Now fill the selected area with SYSMIS */
+ union value sm ;
+ sm.f = SYSMIS;
+ for (x = sel.start_x ; x <= sel.end_x; ++x)
+ {
+ const struct variable * var = psppire_dict_get_variable (dict, x);
+ for (y = sel.start_y ; y <= sel.end_y; ++y)
+ {
+ psppire_data_store_set_value (dw->data_editor->data_store,
+ y,
+ var, &sm);
+ }
+ }
+
}
}
+
+
static void
on_copy (PsppireDataWindow *dw)
{
int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
if (p == 0)
{
- PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
- psppire_data_sheet_edit_copy (ds);
+ GtkClipboard *clip =
+ gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
+ GDK_SELECTION_CLIPBOARD);
+
+ jmd_sheet_set_clip (JMD_SHEET (dw->data_editor->data_sheet), clip);
+ }
+}
+
+
+static void
+trf (GtkClipboard *clip,
+ GdkAtom *atoms,
+ gint n_atoms,
+ gpointer data)
+{
+ int i;
+ for (i = 0; i < n_atoms; ++i)
+ {
+ g_print ("%s\n", gdk_atom_name (atoms[i]));
}
}
int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
if (p == 0)
{
- PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
- psppire_data_sheet_edit_paste (ds);
+ GtkClipboard *clip =
+ gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (dw)),
+ GDK_SELECTION_CLIPBOARD);
+
+ gtk_clipboard_request_targets (clip, trf, dw);
}
}
static void
on_clear_cases (PsppireDataWindow *dw)
{
+#if SHEET_MERGE
int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
if (p == 0)
{
PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
psppire_data_sheet_edit_clear_cases (ds);
}
+#endif
}
static void
on_clear_variables (PsppireDataWindow *dw)
{
+#if SHEET_MERGE
int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
if (p == 0)
{
{
psppire_var_sheet_clear_variables (PSPPIRE_VAR_SHEET (dw->data_editor->var_sheet));
}
+#endif
}
+
static void
insert_variable (PsppireDataWindow *dw)
{
+#if SHEET_MERGE
int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
if (p == 0)
{
{
psppire_var_sheet_insert_variable (PSPPIRE_VAR_SHEET (dw->data_editor->var_sheet));
}
+#endif
}
+
static void
insert_case_at_row (PsppireDataWindow *dw)
{
+#if SHEET_MERGE
PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
psppire_data_sheet_insert_case (ds);
+#endif
}
+
+
static void
goto_case (PsppireDataWindow *dw)
{
- PsppireDataSheet *ds = psppire_data_editor_get_active_data_sheet (dw->data_editor);
-
- goto_case_dialog (ds);
+ int p = gtk_notebook_get_current_page (GTK_NOTEBOOK (dw->data_editor));
+ if (p == 0)
+ {
+ goto_case_dialog (JMD_SHEET (dw->data_editor->data_sheet));
+ }
}
-
static GtkWidget *
create_file_menu (PsppireDataWindow *dw)
{
return menuitem;
}
+
static GtkWidget *
create_edit_menu (PsppireDataWindow *dw)
{
return menuitem;
}
-
static void
psppire_data_window_finish_init (PsppireDataWindow *de,
struct dataset *ds)
G_CALLBACK (on_split_change),
de);
- g_signal_connect_swapped (de->dict, "backend-changed",
+ g_signal_connect_swapped (de->dict, "changed",
G_CALLBACK (enable_save), de);
g_signal_connect_swapped (de->dict, "variable-inserted",
G_CALLBACK (enable_save), de);
ll_push_head (&all_data_windows, &de->ll);
}
+
static void
psppire_data_window_dispose (GObject *object)
{
}
+
GtkWidget*
psppire_data_window_new (struct dataset *ds)
{
return dw;
}
+
+
bool
psppire_data_window_is_empty (PsppireDataWindow *dw)
{
return psppire_dict_get_var_cnt (dw->dict) == 0;
}
+
static void
psppire_data_window_iface_init (PsppireWindowIface *iface)
{
\f
+
PsppireDataWindow *
psppire_default_data_window (void)
{
return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
}
+
+
void
psppire_data_window_set_default (PsppireDataWindow *pdw)
{
ll_push_tail (&all_data_windows, &pdw->ll);
}
-PsppireDataWindow *
-psppire_data_window_for_dataset (struct dataset *ds)
-{
- PsppireDataWindow *pdw;
- ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
- if (pdw->dataset == ds)
- return pdw;
-
- return NULL;
-}
PsppireDataWindow *
-psppire_data_window_for_data_store (PsppireDataStore *data_store)
+psppire_data_window_for_dataset (struct dataset *ds)
{
PsppireDataWindow *pdw;
ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
- if (pdw->data_store == data_store)
+ if (pdw->dataset == ds)
return pdw;
return NULL;
/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2004, 2006, 2007, 2009, 2010, 2011, 2012 Free Software Foundation
+ Copyright (C) 2004, 2006, 2007, 2009, 2010, 2011, 2012, 2016 Free Software Foundation
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
#include "ui/gui/psppire-marshal.h"
#include "ui/gui/psppire-var-ptr.h"
+#include "ui/gui/efficient-sheet/jmd-datum.h"
+
+#include <gobject/genums.h>
+
#include <gettext.h>
#define _(msgid) gettext (msgid)
#define N_(msgid) msgid
+
+
+GType align_enum_type;
+GType measure_enum_type;
+GType role_enum_type;
+
+
enum {
- BACKEND_CHANGED,
+ ITEMS_CHANGED,
VARIABLE_CHANGED,
VARIABLE_INSERTED,
static void dictionary_tree_model_init (GtkTreeModelIface *iface);
+
+static guint
+gni (GListModel *list)
+{
+ PsppireDict *dict = PSPPIRE_DICT (list);
+
+ return psppire_dict_get_var_cnt (dict);
+}
+
+static GType
+git (GListModel *list)
+{
+ return JMD_TYPE_DATUM;
+}
+
+static gpointer
+gi (GListModel *list, guint id)
+{
+ JmdDatum *gd = JMD_DATUM (g_object_new (JMD_TYPE_DATUM, NULL));
+
+ PsppireDict *dict = PSPPIRE_DICT (list);
+
+ if (id >= psppire_dict_get_var_cnt (dict))
+ {
+ gd->text = g_strdup (_("Var"));
+ }
+ else
+ {
+ const struct variable *v = psppire_dict_get_variable (dict, id);
+
+ gd->text = g_strdup (var_get_name (v));
+ gd->label = g_strdup (var_get_label (v));
+ }
+
+ return gd;
+}
+
+
+static void
+jmd_init_iface (GListModelInterface *iface)
+{
+ iface->get_n_items = gni;
+ iface->get_item = gi;
+ iface->get_item_type = git;
+}
+
+
/* --- variables --- */
static GObjectClass *parent_class = NULL;
NULL
};
+ static const GInterfaceInfo list_model_info = {
+ (GInterfaceInitFunc) jmd_init_iface,
+ NULL,
+ NULL
+ };
+
object_type = g_type_register_static (G_TYPE_OBJECT,
"PsppireDict",
&object_info, 0);
-
+
g_type_add_interface_static (object_type, GTK_TYPE_TREE_MODEL,
&tree_model_info);
+
+ g_type_add_interface_static (object_type, G_TYPE_LIST_MODEL,
+ &list_model_info);
}
return object_type;
parent_class = g_type_class_peek_parent (class);
object_class->dispose = psppire_dict_dispose;
-
- signals [BACKEND_CHANGED] =
- g_signal_new ("backend-changed",
+
+ signals [ITEMS_CHANGED] =
+ g_signal_new ("changed",
G_TYPE_FROM_CLASS (class),
G_SIGNAL_RUN_FIRST,
0,
NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
+ psppire_marshal_VOID__UINT_UINT_UINT,
G_TYPE_NONE,
- 0);
+ 3,
+ G_TYPE_UINT,
+ G_TYPE_UINT,
+ G_TYPE_UINT);
signals [VARIABLE_CHANGED] =
PsppireDict *dict = PSPPIRE_DICT (pd);
if ( ! dict->disable_insert_signal)
- g_signal_emit (dict, signals [VARIABLE_INSERTED], 0, idx);
+ {
+ g_signal_emit (dict, signals [VARIABLE_INSERTED], 0, idx);
+ g_signal_emit (dict, signals [ITEMS_CHANGED], 0, idx, 1, 1);
+ }
}
static void
{
g_signal_emit (pd, signals [VARIABLE_DELETED], 0,
var, dict_idx, case_idx);
+ g_signal_emit (pd, signals [ITEMS_CHANGED], 0, dict_idx, 1, 0);
}
static void
mutcb (struct dictionary *d, int idx, unsigned int what, const struct variable *oldvar, void *pd)
{
g_signal_emit (pd, signals [VARIABLE_CHANGED], 0, idx, what, oldvar);
+ g_signal_emit (pd, signals [ITEMS_CHANGED], 0, idx, 1, 1);
}
static void
{
PsppireDict *new_dict = g_object_new (PSPPIRE_TYPE_DICT, NULL);
new_dict->dict = d;
-
+
dict_set_callbacks (new_dict->dict, &gui_callbacks, new_dict);
return new_dict;
{
struct variable *var = dict_get_weight (d);
+ guint old_n = dict_get_var_cnt (dict->dict);
+ guint new_n = dict_get_var_cnt (d);
+
dict->dict = d;
weight_changed_callback (d, var ? var_get_dict_index (var) : -1, dict);
dict_set_callbacks (dict->dict, &gui_callbacks, dict);
- g_signal_emit (dict, signals [BACKEND_CHANGED], 0);
+ g_signal_emit (dict, signals [ITEMS_CHANGED], 0, 0, old_n, new_n);
}
d->disable_insert_signal = FALSE;
g_signal_emit (d, signals[VARIABLE_INSERTED], 0, idx);
-
+ g_signal_emit (d, signals [ITEMS_CHANGED], 0, idx, 0, 1);
+
return var;
}
{
g_return_val_if_fail (PSPPIRE_IS_DICT (model), (GType) 0);
+ GType t = 0;
+
switch (index)
{
case DICT_TVM_COL_NAME:
- return G_TYPE_STRING;
+ case DICT_TVM_COL_LABEL:
+ t = G_TYPE_STRING;
+ break;
+ case DICT_TVM_COL_DECIMAL:
+ case DICT_TVM_COL_WIDTH:
+ case DICT_TVM_COL_COLUMNS:
+ t = G_TYPE_INT;
break;
case DICT_TVM_COL_VAR:
- return PSPPIRE_VAR_PTR_TYPE;
+ t = PSPPIRE_VAR_PTR_TYPE;
break;
- case DICT_TVM_COL_LABEL:
- return G_TYPE_STRING;
+ case DICT_TVM_COL_ALIGNMENT:
+ t = align_enum_type;
break;
- default:
- g_return_val_if_reached ((GType)0);
+ case DICT_TVM_COL_MEASURE:
+ t = measure_enum_type;
+ break;
+ case DICT_TVM_COL_ROLE:
+ t = role_enum_type;
break;
}
- g_assert_not_reached ();
- return ((GType)0);
+ return t;
}
static gboolean
return path;
}
+const struct fmt_spec *var_get_write_format (const struct variable *);
static void
tree_model_get_value (GtkTreeModel *model, GtkTreeIter *iter,
g_return_if_fail (iter->stamp == dict->stamp);
- var = iter->user_data;
+ var = iter->user_data;
+ const struct fmt_spec *fs = var_get_write_format (var);
+
switch (column)
{
case DICT_TVM_COL_NAME:
- {
- g_value_init (value, G_TYPE_STRING);
- g_value_set_string (value, var_get_name (var));
- }
+ g_value_init (value, G_TYPE_STRING);
+ g_value_set_string (value, var_get_name (var));
+ break;
+ case DICT_TVM_COL_WIDTH:
+ g_value_init (value, G_TYPE_INT);
+ g_value_set_int (value, fs->w);
+ break;
+ case DICT_TVM_COL_DECIMAL:
+ g_value_init (value, G_TYPE_INT);
+ g_value_set_int (value, fs->d);
+ break;
+ case DICT_TVM_COL_LABEL:
+ g_value_init (value, G_TYPE_STRING);
+ g_value_set_string (value, var_get_label (var));
+ break;
+ case DICT_TVM_COL_COLUMNS:
+ g_value_init (value, G_TYPE_INT);
+ g_value_set_int (value, var_get_display_width (var));
+ break;
+ case DICT_TVM_COL_ALIGNMENT:
+ g_value_init (value, align_enum_type);
+ g_value_set_enum (value, var_get_alignment (var));
+ break;
+ case DICT_TVM_COL_MEASURE:
+ g_value_init (value, measure_enum_type);
+ g_value_set_enum (value, var_get_measure (var));
+ break;
+ case DICT_TVM_COL_ROLE:
+ g_value_init (value, role_enum_type);
+ g_value_set_enum (value, var_get_role (var));
break;
case DICT_TVM_COL_VAR:
g_value_init (value, PSPPIRE_VAR_PTR_TYPE);
g_value_set_boxed (value, var);
break;
default:
- g_return_if_reached ();
+ g_value_init (value, G_TYPE_STRING);
+ g_value_set_string (value, "????");
break;
}
}
{
PsppireDict *dict = PSPPIRE_DICT (model);
- if ( iter == NULL )
+ if (iter == NULL)
return psppire_dict_get_var_cnt (dict);
return 0;
typedef struct _PsppireDict PsppireDict;
typedef struct _PsppireDictClass PsppireDictClass;
-enum {DICT_TVM_COL_NAME=0, DICT_TVM_COL_VAR, DICT_TVM_COL_LABEL, n_DICT_COLS} ;
+enum {DICT_TVM_COL_NAME=0,
+ DICT_TVM_COL_TYPE,
+ DICT_TVM_COL_WIDTH,
+ DICT_TVM_COL_DECIMAL,
+ DICT_TVM_COL_LABEL,
+ DICT_TVM_COL_VALUE_LABELS,
+ DICT_TVM_COL_MISSING_VALUES,
+ DICT_TVM_COL_COLUMNS,
+ DICT_TVM_COL_ALIGNMENT,
+ DICT_TVM_COL_MEASURE,
+ DICT_TVM_COL_ROLE,
+ DICT_TVM_COL_VAR,
+ n_DICT_COLS} ;
struct _PsppireDict
{
#include "builder-wrapper.h"
#include "helper.h"
-#include "pspp-sheet-view.h"
-#include "pspp-sheet-selection.h"
#include "psppire-import-assistant.h"
#include "psppire-scanf.h"
#include "psppire-dialog.h"
#include "psppire-empty-list-store.h"
#include "psppire-encoding-selector.h"
#include "psppire-spreadsheet-model.h"
-#include "psppire-var-sheet.h"
#include "ui/syntax-gen.h"
#include <gettext.h>
close_assistant (ia, PSPPIRE_RESPONSE_PASTE);
}
+
/* Revises the contents of the fields tree view based on the
currently chosen set of separators. */
static void
return TRUE;
}
+#if SHEET_MERGE
+
static void
render_line_number (PsppSheetViewColumn *tree_column,
}
-
static gint
get_string_width (GtkWidget *treeview, GtkCellRenderer *renderer,
const char *string)
return tree_view;
}
+#endif
+
static GtkWidget *
add_page_to_assistant (PsppireImportAssistant *ia,
GtkWidget *page, GtkAssistantPageType type, const gchar *);
}
-
/* Initializes IA's sheet_spec substructure. */
static void
sheet_spec_page_create (PsppireImportAssistant *ia)
g_object_set_data (G_OBJECT (page), "on-entering", prepare_sheet_spec_page);
}
-
static void
on_chosen (PsppireImportAssistant *ia, GtkWidget *page)
{
on_chosen (ia, page);
}
+
+
static void
chooser_page_enter (PsppireImportAssistant *ia, GtkWidget *page)
{
on_chosen (ia, page);
}
+
+
static void
chooser_page_create (PsppireImportAssistant *ia)
{
}
+
static void
psppire_import_assistant_init (PsppireImportAssistant *ia)
{
}
+#if SHEET_MERGE
+
static void
render_line (PsppSheetViewColumn *tree_column,
GtkCellRenderer *cell,
g_object_set (cell, "text", ds_cstr (&lines[row]), NULL);
}
+#endif
+
/* Sets the widgets to match IA's first_line substructure. */
static void
set_first_line (PsppireImportAssistant *ia)
{
GtkTreePath *path = gtk_tree_path_new_from_indices (ia->skip_lines, -1);
-
+#if SHEET_MERGE
set_model_on_treeview (ia, ia->tree_view, 0);
-
pspp_sheet_view_set_cursor (PSPP_SHEET_VIEW (ia->tree_view),
path, NULL, false);
+#endif
gtk_tree_path_free (path);
gtk_toggle_button_set_active (
ia->skip_lines > 0);
}
+#if SHEET_MERGE
/* Creates and returns a tree view that contains each of the
lines in IA's file as a row. */
}
+
/* Sets IA's first_line substructure to match the widgets. */
static void
set_first_line_options (PsppireImportAssistant *ia)
gtk_widget_set_sensitive (ia->variable_names_cb, ia->skip_lines > 0);
}
+
+
static void
reset_first_line_page (PsppireImportAssistant *ia)
{
gtk_widget_set_sensitive (ia->variable_names_cb, FALSE);
}
-
+#endif
/* Initializes IA's first_line substructure. */
static void
first_line_page_create (PsppireImportAssistant *ia)
add_page_to_assistant (ia, w,
GTK_ASSISTANT_PAGE_CONTENT, _("Select the First Line"));
+#if SHEET_MERGE
+
ia->tree_view = GTK_WIDGET (create_lines_tree_view (
GTK_CONTAINER (get_widget_assert (ia->builder, "first-line-scroller")), ia));
ia->variable_names_cb = get_widget_assert (ia->builder, "variable-names");
g_object_set_data (G_OBJECT (w), "on-reset", reset_first_line_page);
+#endif
}
+
+
static void
intro_on_enter (PsppireImportAssistant *ia)
{
NULL));
}
+
+
\f
struct column
free (ia->columns);
}
+#if SHEET_MERGE
+
/* Called to render one of the cells in the fields preview tree
view. */
static void
(void *) NULL);
}
+#endif
/* Parses the contents of the field at (ROW,COLUMN) according to
its variable format. If OUTPUTP is non-null, then *OUTPUTP
return ok;
}
+#if SHEET_MERGE
/* Called to render one of the cells in the data preview tree
view. */
}
+
\f
free (text);
return TRUE;
}
-
+#endif
\f
}
}
+
+#if SHEET_MERGE
static PsppSheetViewColumn *
make_data_column (PsppireImportAssistant *ia, GtkWidget *tree_view,
bool input, gint dict_idx)
return tree_column;
}
+#endif
static GtkWidget *
create_data_tree_view (gboolean input, GtkContainer *parent,
PsppireImportAssistant *ia)
{
gint i;
+#if SHEET_MERGE
GtkWidget *tree_view = make_tree_view (ia);
set_model_on_treeview (ia, tree_view, ia->skip_lines);
+
+
pspp_sheet_selection_set_mode (pspp_sheet_view_get_selection (PSPP_SHEET_VIEW (tree_view)),
PSPP_SHEET_SELECTION_NONE);
gtk_widget_show (tree_view);
return tree_view;
+#endif
}
+
/* Chooses a name for each column on the separators page */
static void
choose_column_names (PsppireImportAssistant *ia)
\f
+
+#if SHEET_MERGE
+
/* Called when the user changes one of the variables in the
dictionary. */
static void
pop_watch_cursor (ia);
}
-
+#endif
/* Called just before the formats page of the assistant is
static void
prepare_formats_page (PsppireImportAssistant *ia)
{
- PsppireDict *psppire_dict = NULL;
- PsppireVarSheet *var_sheet;
- GtkBin *vars_scroller;
- GtkWidget *old_var_sheet;
-
-
- push_watch_cursor (ia);
-
- if (ia->spreadsheet == NULL)
- {
- struct fmt_guesser *fg;
- unsigned long int number = 0;
- size_t column_idx;
-
-
- ia->dict = dict_create (get_default_encoding ());
- fg = fmt_guesser_create ();
- for (column_idx = 0; column_idx < ia->column_cnt; column_idx++)
- {
- struct variable *modified_var =
- (column_idx < ia->modified_var_cnt ? ia->modified_vars[column_idx] : NULL);
-
- if (modified_var == NULL)
- {
- struct column *column = &ia->columns[column_idx];
- struct variable *var;
- struct fmt_spec format;
- char *name;
- size_t row;
-
- /* Choose variable name. */
- name = dict_make_unique_var_name (ia->dict, column->name, &number);
-
- /* Choose variable format. */
- fmt_guesser_clear (fg);
- for (row = ia->skip_lines; row < ia->line_cnt; row++)
- fmt_guesser_add (fg, column->contents[row]);
- fmt_guesser_guess (fg, &format);
- fmt_fix_input (&format);
-
- /* Create variable. */
- var = dict_create_var_assert (ia->dict, name, fmt_var_width (&format));
- var_set_both_formats (var, &format);
-
- free (name);
- }
- else
- {
- char *name;
-
- name = dict_make_unique_var_name (ia->dict, var_get_name (modified_var),
- &number);
- dict_clone_var_as_assert (ia->dict, modified_var, name);
- free (name);
- }
- }
- fmt_guesser_destroy (fg);
- }
- else
- {
- int row_start = -1;
- int row_stop = -1;
- int col_start = -1;
- int col_stop = -1;
-
- GtkBuilder *builder = ia->builder;
-
- struct casereader *reader = NULL;
-
- GtkWidget *readnames_checkbox = get_widget_assert (builder, "readnames-checkbox");
- GtkWidget *range_entry = get_widget_assert (builder, "cell-range-entry");
- const gchar *range = gtk_entry_get_text (GTK_ENTRY (range_entry));
- GtkWidget *combo_box = get_widget_assert (builder, "sheet-entry");
-
- gint num = gtk_combo_box_get_active (GTK_COMBO_BOX (combo_box));
-
- struct spreadsheet_read_options sro;
-
- sro.sheet_name = NULL;
- sro.cell_range = NULL;
- sro.sheet_index = num + 1;
-
- if ( convert_cell_ref (range, &col_start, &row_start, &col_stop, &row_stop))
- {
- sro.cell_range = g_strdup (range);
- }
-
- sro.read_names = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (readnames_checkbox));
- sro.asw = -1;
-
- switch (ia->spreadsheet->type)
- {
- case SPREADSHEET_ODS:
- case SPREADSHEET_GNUMERIC:
- {
- reader = spreadsheet_make_reader (ia->spreadsheet, &sro);
- ia->dict = dict_clone (ia->spreadsheet->dict);
- }
- break;
- default:
- g_assert_not_reached ();
- break;
- }
- g_free (sro.cell_range);
-
- if (reader && ia->dict)
- {
- struct ccase *c;
- int col;
-
- ia->column_cnt = dict_get_var_cnt (ia->dict);
- ia->columns = xcalloc (ia->column_cnt, sizeof (*ia->columns));
- for (col = 0; col < ia->column_cnt ; ++col)
- {
- const struct variable *var = dict_get_var (ia->dict, col);
- ia->columns[col].name = xstrdup (var_get_name (var));
- ia->columns[col].contents = NULL;
- }
-
- casenumber rows = 0;
- for (; (c = casereader_read (reader)) != NULL; case_unref (c))
- {
- rows++;
- for (col = 0; col < ia->column_cnt ; ++col)
- {
- char *ss;
- const struct variable *var = dict_get_var (ia->dict, col);
-
- ia->columns[col].contents = xrealloc (ia->columns[col].contents,
- sizeof (struct substring) * rows);
-
- ss = data_out (case_data (c, var), dict_get_encoding (ia->dict),
- var_get_print_format (var));
-
- ia->columns[col].contents[rows - 1] = ss_cstr (ss);
- }
-
- if (rows > MAX_PREVIEW_LINES)
- {
- case_unref (c);
- break;
- }
- }
- casereader_destroy (reader);
- ia->line_cnt = rows;
- }
- else
- {
- GtkWidget * dialog = gtk_message_dialog_new (NULL,
- GTK_DIALOG_MODAL,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_CLOSE,
- _("An error occurred reading the spreadsheet file."));
-
- gtk_dialog_run (GTK_DIALOG (dialog));
- gtk_widget_destroy (dialog);
- }
- }
-
- psppire_dict = psppire_dict_new_from_dict (ia->dict);
- g_signal_connect (psppire_dict, "variable-changed",
- G_CALLBACK (on_variable_change), ia);
- ia->psppire_dict = psppire_dict;
-
-
- /* XXX: PsppireVarStore doesn't hold a reference to
- psppire_dict for now, but it should. After it does, we
- should g_object_ref the psppire_dict here, since we also
- hold a reference via ia->formats->dict. */
- var_sheet = PSPPIRE_VAR_SHEET (psppire_var_sheet_new ());
- g_object_set (var_sheet,
- "dictionary", psppire_dict,
- "may-create-vars", FALSE,
- "may-delete-vars", FALSE,
- "format-use", FMT_FOR_INPUT,
- "enable-grid-lines", PSPP_SHEET_VIEW_GRID_LINES_BOTH,
- (void *) NULL);
-
- vars_scroller = GTK_BIN (get_widget_assert (ia->builder, "vars-scroller"));
- old_var_sheet = gtk_bin_get_child (GTK_BIN (vars_scroller));
- if (old_var_sheet != NULL)
- gtk_container_remove (GTK_CONTAINER (vars_scroller), old_var_sheet);
- gtk_container_add (GTK_CONTAINER (vars_scroller), GTK_WIDGET (var_sheet));
- gtk_widget_show (GTK_WIDGET (var_sheet));
-
- ia->data_tree_view =
- GTK_WIDGET (create_data_tree_view (
- FALSE,
- GTK_CONTAINER (get_widget_assert (ia->builder, "data-scroller")),
- ia));
-
- gtk_widget_show (ia->paste_button);
-
- pop_watch_cursor (ia);
}
static void
return ds_cstr (&s);
}
+
gchar *
psppire_import_assistant_generate_syntax (PsppireImportAssistant *ia)
{
struct string s = DS_EMPTY_INITIALIZER;
+#if SHEET_MERGE
if (!ia->spreadsheet)
{
if (ia->file_name == NULL)
{
return sheet_spec_gen_syntax (ia);
}
+
+#endif
return ds_cstr (&s);
}
--- /dev/null
+/*
+ A candidate replacement for Pspp's sheet
+ Copyright (C) 2016 John Darrington
+
+ 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 <config.h>
+#include <gtk/gtk.h>
+
+#include "psppire-var-sheet-header.h"
+
+#include "efficient-sheet/jmd-axis-model.h"
+#include "efficient-sheet/jmd-datum.h"
+
+enum {CHANGED,
+ n_SIGNALS};
+
+static guint signals [n_SIGNALS];
+
+static guint
+gni (GListModel *list)
+{
+ return 11;
+}
+
+static GType
+git (GListModel *list)
+{
+ return JMD_TYPE_DATUM;
+}
+
+static gpointer
+gi (GListModel *list, guint position)
+{
+ JmdDatum *gd = JMD_DATUM (g_object_new (JMD_TYPE_DATUM, NULL));
+
+ switch (position)
+ {
+ case 0:
+ gd->text = g_strdup ("Name");
+ break;
+ case 1:
+ gd->text = g_strdup ("Type");
+ break;
+ case 2:
+ gd->text = g_strdup ("Width");
+ break;
+ case 3:
+ gd->text = g_strdup ("Decimal");
+ break;
+ case 4:
+ gd->text = g_strdup ("Label");
+ break;
+ case 5:
+ gd->text = g_strdup ("Value Labels");
+ break;
+ case 6:
+ gd->text = g_strdup ("Missing Values");
+ break;
+ case 7:
+ gd->text = g_strdup ("Columns");
+ break;
+ case 8:
+ gd->text = g_strdup ("Align");
+ break;
+ case 9:
+ gd->text = g_strdup ("Measure");
+ break;
+ case 10:
+ gd->text = g_strdup ("Role");
+ break;
+ default:
+ // g_assert_not_reached ();
+ g_print ("Bug: Request for item %d\n", position);
+ break;
+ }
+
+ return gd;
+}
+
+
+static void
+psppire_init_iface (GListModelInterface *iface)
+{
+ iface->get_n_items = gni;
+ iface->get_item = gi;
+ iface->get_item_type = git;
+}
+
+
+G_DEFINE_TYPE_WITH_CODE (PsppireVarSheetHeader, psppire_var_sheet_header,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, psppire_init_iface));
+
+static void
+psppire_var_sheet_header_init (PsppireVarSheetHeader *d)
+{
+}
+
+
+
+static void
+psppire_var_sheet_header_class_init (PsppireVarSheetHeaderClass *dc)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (dc);
+
+ /* This signal is never emitted. It is just to satisfy the interface. */
+ signals [CHANGED] =
+ g_signal_new ("changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
--- /dev/null
+/*
+ A candidate replacement for Pspp's sheet
+ Copyright (C) 2016 John Darrington
+
+ 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/>.
+*/
+
+#ifndef _PSPPIRE_VAR_SHEET_HEADER_H
+#define _PSPPIRE_VAR_SHEET_HEADER_H
+
+
+G_DECLARE_FINAL_TYPE (PsppireVarSheetHeader, psppire_var_sheet_header, PSPPIRE, VAR_SHEET_HEADER, GObject)
+
+
+struct _PsppireVarSheetHeader
+{
+ GObject parent_instance;
+};
+
+struct _PsppireVarSheetHeaderClass
+{
+ GObjectClass parent_instance;
+};
+
+
+
+#define PSPPIRE_TYPE_VAR_SHEET_HEADER psppire_var_sheet_header_get_type ()
+
+#endif
+++ /dev/null
-/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2008, 2009, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
-
- 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 <config.h>
-
-#include "ui/gui/psppire-var-sheet.h"
-
-#include "data/format.h"
-#include "data/value-labels.h"
-#include "libpspp/range-set.h"
-#include "ui/gui/builder-wrapper.h"
-#include "ui/gui/helper.h"
-#include "ui/gui/missing-val-dialog.h"
-#include "ui/gui/pspp-sheet-selection.h"
-#include "ui/gui/psppire-cell-renderer-button.h"
-#include "ui/gui/psppire-data-editor.h"
-#include "ui/gui/psppire-data-window.h"
-#include "ui/gui/psppire-dialog-action-var-info.h"
-#include "ui/gui/psppire-dictview.h"
-#include "ui/gui/psppire-empty-list-store.h"
-#include "ui/gui/psppire-marshal.h"
-#include "ui/gui/val-labs-dialog.h"
-#include "ui/gui/var-type-dialog.h"
-#include "ui/gui/var-display.h"
-#include "ui/gui/var-type-dialog.h"
-
-#include "gl/intprops.h"
-
-#include <gettext.h>
-#define _(msgid) gettext (msgid)
-#define N_(msgid) msgid
-
-enum vs_column
- {
- VS_NAME,
- VS_TYPE,
- VS_WIDTH,
- VS_DECIMALS,
- VS_LABEL,
- VS_VALUES,
- VS_MISSING,
- VS_COLUMNS,
- VS_ALIGN,
- VS_MEASURE,
- VS_ROLE
- };
-
-G_DEFINE_TYPE (PsppireVarSheet, psppire_var_sheet, PSPP_TYPE_SHEET_VIEW);
-
-static void
-set_spin_cell (GtkCellRenderer *cell, int value, int min, int max, int step)
-{
- char text[INT_BUFSIZE_BOUND (int)];
- GtkAdjustment *adjust;
-
- if (max > min)
- adjust = GTK_ADJUSTMENT (gtk_adjustment_new (value, min, max,
- step, step, 0.0));
- else
- adjust = NULL;
-
- sprintf (text, "%d", value);
- g_object_set (cell,
- "text", text,
- "adjustment", adjust,
- "editable", TRUE,
- NULL);
-}
-
-static void
-error_dialog (GtkWindow *w, gchar *primary_text, gchar *secondary_text)
-{
- GtkWidget *dialog =
- gtk_message_dialog_new (w,
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_CLOSE, "%s", primary_text);
-
- g_object_set (dialog, "icon-name", "psppicon", NULL);
-
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
- "%s", secondary_text);
-
- gtk_dialog_run (GTK_DIALOG (dialog));
-
- gtk_widget_destroy (dialog);
-}
-
-static void
-on_name_column_editing_started (GtkCellRenderer *cell,
- GtkCellEditable *editable,
- const gchar *path,
- gpointer user_data)
-{
- PsppireVarSheet *var_sheet = g_object_get_data (G_OBJECT (cell), "var-sheet");
- PsppireDict *dict = psppire_var_sheet_get_dictionary (var_sheet);
-
- g_return_if_fail (var_sheet);
- g_return_if_fail (dict);
-
- if (GTK_IS_ENTRY (editable))
- {
- GtkEntry *entry = GTK_ENTRY (editable);
- if (gtk_entry_get_text (entry)[0] == '\0')
- {
- gchar name[64];
- if (psppire_dict_generate_name (dict, name, sizeof name))
- gtk_entry_set_text (entry, name);
- }
- }
-}
-
-static void
-scroll_to_bottom (GtkWidget *widget,
- GtkRequisition *requisition,
- gpointer unused UNUSED)
-{
- PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (widget);
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (widget);
- GtkAdjustment *vadjust;
-
- vadjust = pspp_sheet_view_get_vadjustment (sheet_view);
- gtk_adjustment_set_value (vadjust, gtk_adjustment_get_upper (vadjust));
-
- if (var_sheet->scroll_to_bottom_signal)
- {
- g_signal_handler_disconnect (var_sheet,
- var_sheet->scroll_to_bottom_signal);
- var_sheet->scroll_to_bottom_signal = 0;
- }
-}
-
-static struct variable *
-path_string_to_var (PsppireVarSheet *var_sheet, gchar *path_string)
-{
- GtkTreePath *path;
- gint row;
-
- path = gtk_tree_path_new_from_string (path_string);
- row = gtk_tree_path_get_indices (path)[0];
- gtk_tree_path_free (path);
-
- return psppire_dict_get_variable (var_sheet->dict, row);
-}
-
-static void
-on_var_column_edited (GtkCellRendererText *cell,
- gchar *path_string,
- gchar *new_text,
- gpointer user_data)
-{
- PsppireVarSheet *var_sheet = user_data;
- GtkWindow *window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (var_sheet)));
- struct dictionary *dict = var_sheet->dict->dict;
- enum vs_column column_id;
- struct variable *var;
- int width, decimals;
-
- column_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell),
- "column-id"));
-
- var = path_string_to_var (var_sheet, path_string);
- if (var == NULL)
- {
- g_return_if_fail (column_id == VS_NAME);
-
- if (!dict_id_is_valid (dict, new_text, false))
- error_dialog (window,
- g_strdup (_("Cannot create variable.")),
- g_strdup_printf (_("\"%s\" is not a valid variable "
- "name."), new_text));
- else if (dict_lookup_var (dict, new_text) != NULL)
- error_dialog (window,
- g_strdup (_("Cannot create variable.")),
- g_strdup_printf (_("This dictionary already contains "
- "a variable named \"%s\"."),
- new_text));
- else
- {
- dict_create_var (var_sheet->dict->dict, new_text, 0);
- if (!var_sheet->scroll_to_bottom_signal)
- {
- gtk_widget_queue_resize (GTK_WIDGET (var_sheet));
- var_sheet->scroll_to_bottom_signal =
- g_signal_connect (var_sheet, "size-allocate",
- G_CALLBACK (scroll_to_bottom), NULL);
- }
- }
-
- return;
- }
-
- switch (column_id)
- {
- case VS_NAME:
- if (!dict_id_is_valid (dict, new_text, false))
- error_dialog (window,
- g_strdup (_("Cannot rename variable.")),
- g_strdup_printf (_("\"%s\" is not a valid variable "
- "name."), new_text));
- else if (dict_lookup_var (dict, new_text) != NULL
- && dict_lookup_var (dict, new_text) != var)
- error_dialog (window,
- g_strdup (_("Cannot rename variable.")),
- g_strdup_printf (_("This dictionary already contains "
- "a variable named \"%s\"."),
- new_text));
- else
- dict_rename_var (dict, var, new_text);
- break;
-
- case VS_TYPE:
- /* Not reachable. */
- break;
-
- case VS_WIDTH:
- width = atoi (new_text);
- if (width > 0)
- {
- struct fmt_spec format;
-
- format = *var_get_print_format (var);
- fmt_change_width (&format, width, var_sheet->format_use);
- var_set_width (var, fmt_var_width (&format));
- var_set_both_formats (var, &format);
- }
- break;
-
- case VS_DECIMALS:
- decimals = atoi (new_text);
- if (decimals >= 0)
- {
- struct fmt_spec format;
-
- format = *var_get_print_format (var);
- fmt_change_decimals (&format, decimals, var_sheet->format_use);
- var_set_print_format (var, &format);
- }
- break;
-
- case VS_LABEL:
- var_set_label (var, new_text);
- break;
-
- case VS_VALUES:
- case VS_MISSING:
- break;
-
- case VS_COLUMNS:
- width = atoi (new_text);
- if (width > 0 && width < 2 * MAX_STRING)
- var_set_display_width (var, width);
- break;
-
- case VS_ALIGN:
- if (!strcmp (new_text, alignment_to_string (ALIGN_LEFT)))
- var_set_alignment (var, ALIGN_LEFT);
- else if (!strcmp (new_text, alignment_to_string (ALIGN_CENTRE)))
- var_set_alignment (var, ALIGN_CENTRE);
- else if (!strcmp (new_text, alignment_to_string (ALIGN_RIGHT)))
- var_set_alignment (var, ALIGN_RIGHT);
- break;
-
- case VS_MEASURE:
- if (!strcmp (new_text, measure_to_string (MEASURE_NOMINAL)))
- var_set_measure (var, MEASURE_NOMINAL);
- else if (!strcmp (new_text, measure_to_string (MEASURE_ORDINAL)))
- var_set_measure (var, MEASURE_ORDINAL);
- else if (!strcmp (new_text, measure_to_string (MEASURE_SCALE)))
- var_set_measure (var, MEASURE_SCALE);
- break;
-
- case VS_ROLE:
- if (!strcmp (new_text, var_role_to_string (ROLE_INPUT)))
- var_set_role (var, ROLE_INPUT);
- else if (!strcmp (new_text, var_role_to_string (ROLE_TARGET)))
- var_set_role (var, ROLE_TARGET);
- else if (!strcmp (new_text, var_role_to_string (ROLE_BOTH)))
- var_set_role (var, ROLE_BOTH);
- else if (!strcmp (new_text, var_role_to_string (ROLE_NONE)))
- var_set_role (var, ROLE_NONE);
- else if (!strcmp (new_text, var_role_to_string (ROLE_PARTITION)))
- var_set_role (var, ROLE_PARTITION);
- else if (!strcmp (new_text, var_role_to_string (ROLE_SPLIT)))
- var_set_role (var, ROLE_SPLIT);
- break;
- }
-}
-
-static void
-render_popup_cell (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- void *user_data)
-{
- PsppireVarSheet *var_sheet = user_data;
- gint row;
-
- row = GPOINTER_TO_INT (iter->user_data);
- g_object_set (cell,
- "editable", row < psppire_dict_get_var_cnt (var_sheet->dict),
- NULL);
-}
-
-const char *
-get_var_align_stock_id (enum alignment alignment)
-{
- switch (alignment)
- {
- case ALIGN_LEFT: return "align-left";
- case ALIGN_CENTRE: return "align-center";
- case ALIGN_RIGHT: return "align-right";
- default:
- g_return_val_if_reached ("");
- }
-}
-
-const char *
-get_var_role_stock_id (enum var_role role)
-{
- switch (role)
- {
- case ROLE_INPUT: return "role-input";
- case ROLE_TARGET: return "role-target";
- case ROLE_BOTH: return "role-both";
- case ROLE_NONE: return "role-none";
- case ROLE_PARTITION: return "role-partition";
- case ROLE_SPLIT: return "role-split";
- default:
- g_return_val_if_reached ("");
- }
-}
-
-static void
-render_var_cell (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- void *user_data)
-{
- PsppireVarSheet *var_sheet = user_data;
- const struct fmt_spec *print;
- enum vs_column column_id;
- struct variable *var;
- gint row;
-
- column_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column),
- "column-number")) - 1;
- row = GPOINTER_TO_INT (iter->user_data);
-
- gtk_cell_renderer_set_visible (cell, true);
- if (row >= psppire_dict_get_var_cnt (var_sheet->dict))
- {
- if (GTK_IS_CELL_RENDERER_TEXT (cell))
- {
- g_object_set (cell,
- "text", "",
- "editable", column_id == VS_NAME,
- NULL);
- if (column_id == VS_WIDTH
- || column_id == VS_DECIMALS
- || column_id == VS_COLUMNS)
- g_object_set (cell, "adjustment", NULL, NULL);
- }
- else
- {
- gtk_cell_renderer_set_visible (cell, false);
- }
- return;
- }
-
- var = psppire_dict_get_variable (var_sheet->dict, row);
-
- print = var_get_print_format (var);
- switch (column_id)
- {
- case VS_NAME:
- g_object_set (cell,
- "text", var_get_name (var),
- "editable", TRUE,
- NULL);
- break;
-
- case VS_TYPE:
- g_object_set (cell,
- "text", fmt_gui_name (print->type),
- "editable", FALSE,
- NULL);
- break;
-
- case VS_WIDTH:
- set_spin_cell (cell, print->w,
- fmt_min_width (print->type, var_sheet->format_use),
- fmt_max_width (print->type, var_sheet->format_use),
- fmt_step_width (print->type));
- break;
-
- case VS_DECIMALS:
- if (fmt_takes_decimals (print->type))
- {
- int max_w = fmt_max_width (print->type, var_sheet->format_use);
- int max_d = fmt_max_decimals (print->type, max_w,
- var_sheet->format_use);
- set_spin_cell (cell, print->d, 0, max_d, 1);
- }
- else
- g_object_set (cell,
- "text", "",
- "editable", FALSE,
- "adjustment", NULL,
- NULL);
- break;
-
- case VS_LABEL:
- g_object_set (cell,
- "text", var_has_label (var) ? var_get_label (var) : "",
- "editable", TRUE,
- NULL);
- break;
-
- case VS_VALUES:
- g_object_set (cell, "editable", FALSE, NULL);
- if ( ! var_has_value_labels (var))
- g_object_set (cell, "text", _("None"), NULL);
- else
- {
- const struct val_labs *vls = var_get_value_labels (var);
- const struct val_lab **labels = val_labs_sorted (vls);
- const struct val_lab *vl = labels[0];
- gchar *vstr = value_to_text (vl->value, var);
- char *text = xasprintf (_("{%s, %s}..."), vstr,
- val_lab_get_escaped_label (vl));
- free (vstr);
-
- g_object_set (cell, "text", text, NULL);
- free (text);
- free (labels);
- }
- break;
-
- case VS_MISSING:
- {
- char *text = missing_values_to_string (var, NULL);
- g_object_set (cell,
- "text", text,
- "editable", FALSE,
- NULL);
- free (text);
- }
- break;
-
- case VS_COLUMNS:
- set_spin_cell (cell, var_get_display_width (var), 1, 2 * MAX_STRING, 1);
- break;
-
- case VS_ALIGN:
- if (GTK_IS_CELL_RENDERER_TEXT (cell))
- g_object_set (cell,
- "text", alignment_to_string (var_get_alignment (var)),
- "editable", TRUE,
- NULL);
- else
- g_object_set (cell, "icon-name",
- get_var_align_stock_id (var_get_alignment (var)), NULL);
- break;
-
- case VS_MEASURE:
- if (GTK_IS_CELL_RENDERER_TEXT (cell))
- g_object_set (cell,
- "text", measure_to_string (var_get_measure (var)),
- "editable", TRUE,
- NULL);
- else
- {
- enum fmt_type type = var_get_print_format (var)->type;
- enum measure measure = var_get_measure (var);
-
- g_object_set (cell, "icon-name",
- get_var_measurement_stock_id (type, measure),
- NULL);
- }
- break;
-
- case VS_ROLE:
- if (GTK_IS_CELL_RENDERER_TEXT (cell))
- g_object_set (cell,
- "text", var_role_to_string (var_get_role (var)),
- "editable", TRUE,
- NULL);
- else
- g_object_set (cell, "icon-name",
- get_var_role_stock_id (var_get_role (var)), NULL);
- break;
- }
-}
-
-static struct variable *
-path_string_to_variable (PsppireVarSheet *var_sheet, gchar *path_string)
-{
- PsppireDict *dict;
- GtkTreePath *path;
- gint row;
-
- path = gtk_tree_path_new_from_string (path_string);
- row = gtk_tree_path_get_indices (path)[0];
- gtk_tree_path_free (path);
-
- dict = psppire_var_sheet_get_dictionary (var_sheet);
- g_return_val_if_fail (dict != NULL, NULL);
-
- return psppire_dict_get_variable (dict, row);
-}
-
-static void
-on_type_click (PsppireCellRendererButton *cell,
- gchar *path,
- PsppireVarSheet *var_sheet)
-{
- GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (var_sheet));
- struct fmt_spec format;
- struct variable *var;
-
- var = path_string_to_variable (var_sheet, path);
- g_return_if_fail (var != NULL);
-
- format = *var_get_print_format (var);
- psppire_var_type_dialog_run (GTK_WINDOW (toplevel), &format);
-
- var_set_width_and_formats (var, fmt_var_width (&format), &format, &format);
-}
-
-static void
-on_value_labels_click (PsppireCellRendererButton *cell,
- gchar *path,
- PsppireVarSheet *var_sheet)
-{
- GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (var_sheet));
- struct val_labs *labels;
- struct variable *var;
-
- var = path_string_to_variable (var_sheet, path);
- g_return_if_fail (var != NULL);
-
- labels = psppire_val_labs_dialog_run (GTK_WINDOW (toplevel), var);
- if (labels)
- {
- var_set_value_labels (var, labels);
- val_labs_destroy (labels);
- }
-}
-
-static void
-on_missing_values_click (PsppireCellRendererButton *cell,
- gchar *path,
- PsppireVarSheet *var_sheet)
-{
- GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (var_sheet));
- struct missing_values mv;
- struct variable *var;
-
- var = path_string_to_variable (var_sheet, path);
- g_return_if_fail (var != NULL);
-
- psppire_missing_val_dialog_run (GTK_WINDOW (toplevel), var, &mv);
- var_set_missing_values (var, &mv);
- mv_destroy (&mv);
-}
-
-static gint
-get_string_width (PsppSheetView *treeview, GtkCellRenderer *renderer,
- const char *string)
-{
- gint width;
- g_object_set (G_OBJECT (renderer),
- PSPPIRE_IS_CELL_RENDERER_BUTTON (renderer) ? "label" : "text",
- string, (void *) NULL);
-
- gtk_cell_renderer_get_preferred_width (renderer, GTK_WIDGET (treeview), NULL, &width);
-
- return width;
-}
-
-static gint
-get_monospace_width (PsppSheetView *treeview, GtkCellRenderer *renderer,
- size_t char_cnt)
-{
- struct string s;
- gint width;
-
- ds_init_empty (&s);
- ds_put_byte_multiple (&s, '0', char_cnt);
- ds_put_byte (&s, ' ');
- width = get_string_width (treeview, renderer, ds_cstr (&s));
- ds_destroy (&s);
-
- return width;
-}
-
-static PsppSheetViewColumn *
-add_var_sheet_column (PsppireVarSheet *var_sheet, GtkCellRenderer *renderer,
- enum vs_column column_id,
- const char *title, int width)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
- int title_width, content_width;
- PsppSheetViewColumn *column;
-
- column = pspp_sheet_view_column_new_with_attributes (title, renderer, NULL);
- g_object_set_data (G_OBJECT (column), "column-number",
- GINT_TO_POINTER (column_id) + 1);
-
- pspp_sheet_view_column_set_cell_data_func (
- column, renderer, render_var_cell, var_sheet, NULL);
-
- title_width = get_string_width (sheet_view, renderer, title);
- content_width = get_monospace_width (sheet_view, renderer, width);
- g_object_set_data (G_OBJECT (column), "content-width",
- GINT_TO_POINTER (content_width));
-
- pspp_sheet_view_column_set_fixed_width (column,
- MAX (title_width, content_width));
- pspp_sheet_view_column_set_resizable (column, TRUE);
-
- pspp_sheet_view_append_column (sheet_view, column);
-
- g_signal_connect (renderer, "edited",
- G_CALLBACK (on_var_column_edited),
- var_sheet);
- g_object_set_data (G_OBJECT (renderer), "column-id",
- GINT_TO_POINTER (column_id));
- g_object_set_data (G_OBJECT (renderer), "var-sheet", var_sheet);
-
- return column;
-}
-
-static PsppSheetViewColumn *
-add_text_column (PsppireVarSheet *var_sheet, enum vs_column column_id,
- const char *title, int width)
-{
- return add_var_sheet_column (var_sheet, gtk_cell_renderer_text_new (),
- column_id, title, width);
-}
-
-static PsppSheetViewColumn *
-add_spin_column (PsppireVarSheet *var_sheet, enum vs_column column_id,
- const char *title, int width)
-{
- return add_var_sheet_column (var_sheet, gtk_cell_renderer_spin_new (),
- column_id, title, width);
-}
-
-static const char *
-measure_to_stock_id (enum fmt_type type, int measure)
-{
- return get_var_measurement_stock_id (type, measure);
-}
-
-static const char *
-alignment_to_stock_id (enum fmt_type type, int alignment)
-{
- return get_var_align_stock_id (alignment);
-}
-
-static const char *
-role_to_stock_id (enum fmt_type type, int role)
-{
- return get_var_role_stock_id (role);
-}
-
-static void
-render_var_pixbuf (GtkCellLayout *cell_layout,
- GtkCellRenderer *cell,
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- gpointer data)
-{
- const char *(*value_to_stock_id) (enum fmt_type, int value);
- enum fmt_type type = GPOINTER_TO_INT (data);
- gint value;
-
- value_to_stock_id = g_object_get_data (G_OBJECT (cell), "value-to-stock-id");
-
- gtk_tree_model_get (tree_model, iter, 0, &value, -1);
- g_object_set (cell, "icon-name", value_to_stock_id (type, value), NULL);
-}
-
-static void
-on_combo_editing_started (GtkCellRenderer *renderer,
- GtkCellEditable *editable,
- gchar *path_string,
- gpointer user_data)
-{
- PsppireVarSheet *var_sheet = user_data;
-
- if (GTK_IS_COMBO_BOX (editable))
- {
- struct variable *var = path_string_to_variable (var_sheet, path_string);
- const struct fmt_spec *format = var_get_print_format (var);
- const char *(*value_to_stock_id) (enum fmt_type, int value);
- GtkCellRenderer *cell;
-
- value_to_stock_id = g_object_get_data (G_OBJECT (renderer),
- "value-to-stock-id");
-
- cell = gtk_cell_renderer_pixbuf_new ();
- g_object_set (cell, "width", 16, "height", 16, NULL);
- g_object_set_data (G_OBJECT (cell),
- "value-to-stock-id", value_to_stock_id);
- gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (editable), cell, FALSE);
- gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (editable), cell,
- render_var_pixbuf,
- GINT_TO_POINTER (format->type),
- NULL);
- }
-}
-
-static void
-add_combo_column (PsppireVarSheet *var_sheet, enum vs_column column_id,
- const char *title, int width,
- const char *(*value_to_stock_id) (enum fmt_type, int value),
- ...)
-{
- PsppSheetViewColumn *column;
- GtkCellRenderer *cell;
- GtkListStore *store;
- const char *name;
- va_list args;
-
- store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
- va_start (args, value_to_stock_id);
- while ((name = va_arg (args, const char *)) != NULL)
- {
- int value = va_arg (args, int);
- gtk_list_store_insert_with_values (store, NULL, G_MAXINT,
- 0, value,
- 1, name,
- -1);
- }
- va_end (args);
-
- cell = gtk_cell_renderer_combo_new ();
- g_object_set (cell,
- "has-entry", FALSE,
- "model", GTK_TREE_MODEL (store),
- "text-column", 1,
- NULL);
- if (value_to_stock_id != NULL)
- {
- g_object_set_data (G_OBJECT (cell),
- "value-to-stock-id", value_to_stock_id);
- g_signal_connect (cell, "editing-started",
- G_CALLBACK (on_combo_editing_started),
- var_sheet);
- }
-
- column = add_var_sheet_column (var_sheet, cell, column_id, title, width);
-
- cell = gtk_cell_renderer_pixbuf_new ();
- g_object_set (cell, "width", 16, "height", 16, NULL);
- pspp_sheet_view_column_pack_end (column, cell, FALSE);
- pspp_sheet_view_column_set_cell_data_func (
- column, cell, render_var_cell, var_sheet, NULL);
-}
-
-static void
-add_popup_menu (PsppireVarSheet *var_sheet,
- PsppSheetViewColumn *column,
- void (*on_click) (PsppireCellRendererButton *,
- gchar *path,
- PsppireVarSheet *var_sheet))
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
- const char *button_label = "...";
- GtkCellRenderer *button_renderer;
- gint content_width;
-
- button_renderer = psppire_cell_renderer_button_new ();
- g_object_set (button_renderer,
- "label", button_label,
- "editable", TRUE,
- NULL);
- g_signal_connect (button_renderer, "clicked", G_CALLBACK (on_click),
- var_sheet);
- pspp_sheet_view_column_pack_start (column, button_renderer, FALSE);
- pspp_sheet_view_column_set_cell_data_func (
- column, button_renderer, render_popup_cell, var_sheet, NULL);
-
- content_width = GPOINTER_TO_INT (g_object_get_data (
- G_OBJECT (column), "content-width"));
- content_width += get_string_width (sheet_view, button_renderer,
- button_label);
- if (content_width > pspp_sheet_view_column_get_fixed_width (column))
- pspp_sheet_view_column_set_fixed_width (column, content_width);
-}
-
-static gboolean
-get_tooltip_location (GtkWidget *widget, GtkTooltip *tooltip,
- gint wx, gint wy, size_t *row, size_t *column)
-{
- PsppSheetView *tree_view = PSPP_SHEET_VIEW (widget);
- gint bx, by;
- GtkTreePath *path;
- GtkTreeIter iter;
- PsppSheetViewColumn *tree_column;
- GtkTreeModel *tree_model;
- gpointer column_ptr;
- bool ok;
-
- /* Check that WIDGET is really visible on the screen before we
- do anything else. This is a bug fix for a sticky situation:
- when text_data_import_assistant() returns, it frees the data
- necessary to compose the tool tip message, but there may be
- a tool tip under preparation at that point (even if there is
- no visible tool tip) that will call back into us a little
- bit later. Perhaps the correct solution to this problem is
- to make the data related to the tool tips part of a GObject
- that only gets destroyed when all references are released,
- but this solution appears to be effective too. */
- if (!gtk_widget_get_mapped (widget))
- return FALSE;
-
- pspp_sheet_view_convert_widget_to_bin_window_coords (tree_view,
- wx, wy, &bx, &by);
- if (!pspp_sheet_view_get_path_at_pos (tree_view, bx, by,
- &path, &tree_column, NULL, NULL))
- return FALSE;
-
- column_ptr = g_object_get_data (G_OBJECT (tree_column), "column-number");
- if (column_ptr == NULL)
- return FALSE;
- *column = GPOINTER_TO_INT (column_ptr) - 1;
-
- pspp_sheet_view_set_tooltip_cell (tree_view, tooltip, path, tree_column,
- NULL);
-
- tree_model = pspp_sheet_view_get_model (tree_view);
- ok = gtk_tree_model_get_iter (tree_model, &iter, path);
- gtk_tree_path_free (path);
- if (!ok)
- return FALSE;
-
- *row = GPOINTER_TO_INT (iter.user_data);
- return TRUE;
-}
-
-static gboolean
-on_query_var_tooltip (GtkWidget *widget, gint wx, gint wy,
- gboolean keyboard_mode UNUSED,
- GtkTooltip *tooltip, gpointer *user_data UNUSED)
-{
- PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (widget);
- PsppireDict *dict;
- struct variable *var;
- size_t row, column;
-
- if (!get_tooltip_location (widget, tooltip, wx, wy, &row, &column))
- return FALSE;
-
- dict = psppire_var_sheet_get_dictionary (var_sheet);
- g_return_val_if_fail (dict != NULL, FALSE);
-
- if (row >= psppire_dict_get_var_cnt (dict))
- {
- gtk_tooltip_set_text (tooltip, _("Enter a variable name to add a "
- "new variable."));
- return TRUE;
- }
-
- var = psppire_dict_get_variable (dict, row);
- g_return_val_if_fail (var != NULL, FALSE);
-
- switch (column)
- {
- case VS_TYPE:
- {
- char text[FMT_STRING_LEN_MAX + 1];
-
- fmt_to_string (var_get_print_format (var), text);
- gtk_tooltip_set_text (tooltip, text);
- return TRUE;
- }
-
- case VS_VALUES:
- if (var_has_value_labels (var))
- {
- const struct val_labs *vls = var_get_value_labels (var);
- const struct val_lab **labels = val_labs_sorted (vls);
- struct string s;
- size_t i;
-
- ds_init_empty (&s);
- for (i = 0; i < val_labs_count (vls); i++)
- {
- const struct val_lab *vl = labels[i];
- gchar *vstr;
-
- if (i >= 10 || ds_length (&s) > 500)
- {
- ds_put_cstr (&s, "...");
- break;
- }
-
- vstr = value_to_text (vl->value, var);
- ds_put_format (&s, _("{%s, %s}\n"), vstr,
- val_lab_get_escaped_label (vl));
- free (vstr);
-
- }
- ds_chomp_byte (&s, '\n');
-
- gtk_tooltip_set_text (tooltip, ds_cstr (&s));
- ds_destroy (&s);
- free (labels);
-
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-static void
-do_popup_menu (GtkWidget *widget, guint button, guint32 time)
-{
- PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (widget);
- GtkWidget *menu = gtk_menu_new ();
-
- int i = 0;
-
- GtkWidget *insert_variable = gtk_menu_item_new_with_mnemonic (_("_Insert Variable"));
- GtkWidget *clear_variables = gtk_menu_item_new_with_mnemonic (_("Cl_ear Variables"));
-
- g_signal_connect_swapped (insert_variable, "activate", G_CALLBACK (psppire_var_sheet_insert_variable), var_sheet);
- g_signal_connect_swapped (clear_variables, "activate", G_CALLBACK (psppire_var_sheet_clear_variables), var_sheet);
-
- gtk_menu_attach (GTK_MENU (menu), insert_variable, 0, 1, i, i + 1); ++i;
- gtk_menu_attach (GTK_MENU (menu), clear_variables, 0, 1, i, i + 1); ++i;
-
- gtk_widget_show_all (menu);
-
- gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, button, time);
-}
-
-static void
-on_popup_menu (GtkWidget *widget, gpointer user_data UNUSED)
-{
- do_popup_menu (widget, 0, gtk_get_current_event_time ());
-}
-
-static gboolean
-on_button_pressed (GtkWidget *widget, GdkEventButton *event,
- gpointer user_data UNUSED)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (widget);
-
- if (event->type == GDK_BUTTON_PRESS && event->button == 3)
- {
- PsppSheetSelection *selection;
-
- selection = pspp_sheet_view_get_selection (sheet_view);
- if (pspp_sheet_selection_count_selected_rows (selection) <= 1)
- {
- GtkTreePath *path;
-
- if (pspp_sheet_view_get_path_at_pos (sheet_view, event->x, event->y,
- &path, NULL, NULL, NULL))
- {
- pspp_sheet_selection_unselect_all (selection);
- pspp_sheet_selection_select_path (selection, path);
- gtk_tree_path_free (path);
- }
- }
-
- do_popup_menu (widget, event->button, event->time);
- return TRUE;
- }
-
- return FALSE;
-}
-
-\f
-GType
-psppire_fmt_use_get_type (void)
-{
- static GType etype = 0;
- if (etype == 0)
- {
- static const GEnumValue values[] =
- {
- { FMT_FOR_INPUT, "FMT_FOR_INPUT", "input" },
- { FMT_FOR_OUTPUT, "FMT_FOR_OUTPUT", "output" },
- { 0, NULL, NULL }
- };
-
- etype = g_enum_register_static
- (g_intern_static_string ("PsppireFmtUse"), values);
- }
- return etype;
-}
-
-enum
- {
- PROP_0,
- PROP_DICTIONARY,
- PROP_MAY_CREATE_VARS,
- PROP_MAY_DELETE_VARS,
- PROP_FORMAT_TYPE
- };
-
-static void
-psppire_var_sheet_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- PsppireVarSheet *obj = PSPPIRE_VAR_SHEET (object);
-
- switch (prop_id)
- {
- case PROP_DICTIONARY:
- psppire_var_sheet_set_dictionary (obj,
- PSPPIRE_DICT (g_value_get_object (
- value)));
- break;
-
- case PROP_MAY_CREATE_VARS:
- psppire_var_sheet_set_may_create_vars (obj,
- g_value_get_boolean (value));
- break;
-
- case PROP_MAY_DELETE_VARS:
- psppire_var_sheet_set_may_delete_vars (obj,
- g_value_get_boolean (value));
- break;
-
- case PROP_FORMAT_TYPE:
- obj->format_use = g_value_get_enum (value);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-psppire_var_sheet_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- PsppireVarSheet *obj = PSPPIRE_VAR_SHEET (object);
-
- switch (prop_id)
- {
- case PROP_DICTIONARY:
- g_value_set_object (value,
- G_OBJECT (psppire_var_sheet_get_dictionary (obj)));
- break;
-
- case PROP_MAY_CREATE_VARS:
- g_value_set_boolean (value, obj->may_create_vars);
- break;
-
- case PROP_MAY_DELETE_VARS:
- g_value_set_boolean (value, obj->may_delete_vars);
- break;
-
- case PROP_FORMAT_TYPE:
- g_value_set_enum (value, obj->format_use);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-psppire_var_sheet_dispose (GObject *obj)
-{
- PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (obj);
- int i;
-
- if (var_sheet->dispose_has_run)
- return;
-
- var_sheet->dispose_has_run = TRUE;
-
- for (i = 0; i < PSPPIRE_VAR_SHEET_N_SIGNALS; i++)
- if ( var_sheet->dict_signals[i])
- g_signal_handler_disconnect (var_sheet->dict,
- var_sheet->dict_signals[i]);
-
- if (var_sheet->dict)
- g_object_unref (var_sheet->dict);
-
- /* These dialogs are not GObjects (although they should be!)
- But for now, unreffing them only causes a GCritical Error
- so comment them out for now. (and accept the memory leakage)
-
- g_object_unref (var_sheet->val_labs_dialog);
- g_object_unref (var_sheet->missing_val_dialog);
- g_object_unref (var_sheet->var_type_dialog);
- */
-
- G_OBJECT_CLASS (psppire_var_sheet_parent_class)->dispose (obj);
-}
-
-static void
-psppire_var_sheet_class_init (PsppireVarSheetClass *class)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (class);
- GParamSpec *pspec;
-
- gobject_class->set_property = psppire_var_sheet_set_property;
- gobject_class->get_property = psppire_var_sheet_get_property;
- gobject_class->dispose = psppire_var_sheet_dispose;
-
- g_signal_new ("var-double-clicked",
- G_OBJECT_CLASS_TYPE (gobject_class),
- G_SIGNAL_RUN_LAST,
- 0,
- g_signal_accumulator_true_handled, NULL,
- psppire_marshal_BOOLEAN__INT,
- G_TYPE_BOOLEAN, 1, G_TYPE_INT);
-
- pspec = g_param_spec_object ("dictionary",
- "Dictionary displayed by the sheet",
- "The PsppireDict that the sheet displays "
- "may allow the user to edit",
- PSPPIRE_TYPE_DICT,
- G_PARAM_READWRITE);
- g_object_class_install_property (gobject_class, PROP_DICTIONARY, pspec);
-
- pspec = g_param_spec_boolean ("may-create-vars",
- "May create variables",
- "Whether the user may create more variables",
- TRUE,
- G_PARAM_READWRITE);
- g_object_class_install_property (gobject_class, PROP_MAY_CREATE_VARS, pspec);
-
- pspec = g_param_spec_boolean ("may-delete-vars",
- "May delete variables",
- "Whether the user may delete variables",
- TRUE,
- G_PARAM_READWRITE);
- g_object_class_install_property (gobject_class, PROP_MAY_DELETE_VARS, pspec);
-
- pspec = g_param_spec_enum ("format-use",
- "Use of variable format",
- ("Whether variables have input or output "
- "formats"),
- PSPPIRE_TYPE_FMT_USE,
- FMT_FOR_OUTPUT,
- G_PARAM_READWRITE);
- g_object_class_install_property (gobject_class, PROP_FORMAT_TYPE, pspec);
-}
-
-static void
-render_row_number_cell (PsppSheetViewColumn *tree_column,
- GtkCellRenderer *cell,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer user_data)
-{
- PsppireVarSheet *var_sheet = user_data;
- GValue gvalue = { 0, };
- gint row;
-
- row = GPOINTER_TO_INT (iter->user_data);
-
- g_value_init (&gvalue, G_TYPE_INT);
- g_value_set_int (&gvalue, row + 1);
- g_object_set_property (G_OBJECT (cell), "label", &gvalue);
- g_value_unset (&gvalue);
-
- if (!var_sheet->dict || row < psppire_dict_get_var_cnt (var_sheet->dict))
- g_object_set (cell, "editable", TRUE, NULL);
- else
- g_object_set (cell, "editable", FALSE, NULL);
-}
-
-static void
-psppire_var_sheet_row_number_double_clicked (PsppireCellRendererButton *button,
- gchar *path_string,
- PsppireVarSheet *var_sheet)
-{
- GtkTreePath *path;
-
- g_return_if_fail (var_sheet->dict != NULL);
-
- path = gtk_tree_path_new_from_string (path_string);
- if (gtk_tree_path_get_depth (path) == 1)
- {
- gint *indices = gtk_tree_path_get_indices (path);
- if (indices[0] < psppire_dict_get_var_cnt (var_sheet->dict))
- {
- gboolean handled;
- g_signal_emit_by_name (var_sheet, "var-double-clicked",
- indices[0], &handled);
- }
- }
- gtk_tree_path_free (path);
-}
-
-static void
-psppire_var_sheet_variables_column_clicked (PsppSheetViewColumn *column,
- PsppireVarSheet *var_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
- PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
-
- pspp_sheet_selection_select_all (selection);
-}
-
-static PsppSheetViewColumn *
-make_row_number_column (PsppireVarSheet *var_sheet)
-{
- PsppSheetViewColumn *column;
- GtkCellRenderer *renderer;
-
- renderer = psppire_cell_renderer_button_new ();
- g_object_set (renderer, "xalign", 1.0, NULL);
- g_signal_connect (renderer, "double-clicked",
- G_CALLBACK (psppire_var_sheet_row_number_double_clicked),
- var_sheet);
-
- column = pspp_sheet_view_column_new_with_attributes (_("Variable"),
- renderer, NULL);
- pspp_sheet_view_column_set_clickable (column, TRUE);
- pspp_sheet_view_column_set_cell_data_func (
- column, renderer, render_row_number_cell, var_sheet, NULL);
- pspp_sheet_view_column_set_fixed_width (column, 50);
- g_signal_connect (column, "clicked",
- G_CALLBACK (psppire_var_sheet_variables_column_clicked),
- var_sheet);
-
- return column;
-}
-
-void
-psppire_var_sheet_clear_variables (PsppireVarSheet *var_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
- PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
- PsppireDict *dict = var_sheet->dict;
- const struct range_set_node *node;
- struct range_set *selected = pspp_sheet_selection_get_range_set (selection);
-
- for (node = range_set_last (selected); node != NULL;
- node = range_set_prev (selected, node))
- {
- int i;
-
- for (i = 1; i <= range_set_node_get_width (node); i++)
- {
- unsigned long row = range_set_node_get_end (node) - i;
- if (row < psppire_dict_get_var_cnt (dict))
- psppire_dict_delete_variables (dict, row, 1);
- }
- }
- range_set_destroy (selected);
-}
-
-static void
-on_selection_changed (PsppSheetSelection *selection,
- gpointer user_data UNUSED)
-{
- PsppSheetView *sheet_view = pspp_sheet_selection_get_tree_view (selection);
- PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (sheet_view);
- gint n_selected_rows = pspp_sheet_selection_count_selected_rows (selection);
- gboolean may_delete;
- GtkTreePath *path;
-
- GtkWidget *top = gtk_widget_get_toplevel (GTK_WIDGET (var_sheet));
- if (! PSPPIRE_IS_DATA_WINDOW (top))
- return;
-
- PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (top);
- gtk_widget_set_sensitive (dw->mi_insert_var, n_selected_rows > 0);
-
- switch (n_selected_rows)
- {
- case 0:
- may_delete = FALSE;
- break;
-
- case 1:
- /* The row used for inserting new variables cannot be deleted. */
- path = gtk_tree_path_new_from_indices (
- psppire_dict_get_var_cnt (var_sheet->dict), -1);
- may_delete = !pspp_sheet_selection_path_is_selected (selection, path);
- gtk_tree_path_free (path);
- break;
-
- default:
- may_delete = TRUE;
- break;
- }
-
- gtk_widget_set_sensitive (dw->mi_clear_variables, var_sheet->may_delete_vars && may_delete);
-}
-
-void
-psppire_var_sheet_insert_variable (PsppireVarSheet *var_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
- PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
- PsppireDict *dict = var_sheet->dict;
- struct range_set *selected;
- unsigned long row;
-
- selected = pspp_sheet_selection_get_range_set (selection);
- row = range_set_scan (selected, 0);
- range_set_destroy (selected);
-
- if (row <= psppire_dict_get_var_cnt (dict))
- {
- gchar name[64];;
- if (psppire_dict_generate_name (dict, name, sizeof name))
- psppire_dict_insert_variable (dict, row, name);
- }
-}
-
-static void
-psppire_var_sheet_init (PsppireVarSheet *obj)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (obj);
- PsppSheetViewColumn *column;
- GList *list;
-
- obj->dict = NULL;
- obj->format_use = FMT_FOR_OUTPUT;
- obj->may_create_vars = TRUE;
- obj->may_delete_vars = TRUE;
-
- obj->scroll_to_bottom_signal = 0;
-
- obj->container = NULL;
- obj->dispose_has_run = FALSE;
-
- pspp_sheet_view_append_column (sheet_view, make_row_number_column (obj));
-
- column = add_text_column (obj, VS_NAME, _("Name"), 12);
- list = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
- g_signal_connect (list->data, "editing-started",
- G_CALLBACK (on_name_column_editing_started), NULL);
- g_list_free (list);
-
- column = add_text_column (obj, VS_TYPE, _("Type"), 8);
- add_popup_menu (obj, column, on_type_click);
-
- add_spin_column (obj, VS_WIDTH, _("Width"), 5);
-
- add_spin_column (obj, VS_DECIMALS, _("Decimals"), 2);
-
- add_text_column (obj, VS_LABEL, _("Label"), 20);
-
- column = add_text_column (obj, VS_VALUES, _("Value Labels"), 20);
- add_popup_menu (obj, column, on_value_labels_click);
-
- column = add_text_column (obj, VS_MISSING, _("Missing Values"), 20);
- add_popup_menu (obj, column, on_missing_values_click);
-
- add_spin_column (obj, VS_COLUMNS, _("Columns"), 3);
-
- add_combo_column (obj, VS_ALIGN, _("Align"), 8, alignment_to_stock_id,
- alignment_to_string (ALIGN_LEFT), ALIGN_LEFT,
- alignment_to_string (ALIGN_CENTRE), ALIGN_CENTRE,
- alignment_to_string (ALIGN_RIGHT), ALIGN_RIGHT,
- NULL);
-
- add_combo_column (obj, VS_MEASURE, _("Measure"), 11, measure_to_stock_id,
- measure_to_string (MEASURE_NOMINAL), MEASURE_NOMINAL,
- measure_to_string (MEASURE_ORDINAL), MEASURE_ORDINAL,
- measure_to_string (MEASURE_SCALE), MEASURE_SCALE,
- NULL);
-
- add_combo_column (obj, VS_ROLE, _("Role"), 11, role_to_stock_id,
- var_role_to_string (ROLE_INPUT), ROLE_INPUT,
- var_role_to_string (ROLE_TARGET), ROLE_TARGET,
- var_role_to_string (ROLE_BOTH), ROLE_BOTH,
- var_role_to_string (ROLE_NONE), ROLE_NONE,
- var_role_to_string (ROLE_PARTITION), ROLE_PARTITION,
- var_role_to_string (ROLE_SPLIT), ROLE_SPLIT,
- NULL);
-
- pspp_sheet_view_set_rubber_banding (sheet_view, TRUE);
- pspp_sheet_selection_set_mode (pspp_sheet_view_get_selection (sheet_view),
- PSPP_SHEET_SELECTION_MULTIPLE);
-
- g_object_set (G_OBJECT (obj), "has-tooltip", TRUE, NULL);
- g_signal_connect (obj, "query-tooltip",
- G_CALLBACK (on_query_var_tooltip), NULL);
- g_signal_connect (obj, "button-press-event",
- G_CALLBACK (on_button_pressed), NULL);
-
- g_signal_connect (obj, "popup-menu", G_CALLBACK (on_popup_menu), NULL);
-
- g_signal_connect (pspp_sheet_view_get_selection (sheet_view),
- "changed", G_CALLBACK (on_selection_changed), NULL);
-}
-
-GtkWidget *
-psppire_var_sheet_new (void)
-{
- return g_object_new (PSPPIRE_VAR_SHEET_TYPE, NULL);
-}
-
-PsppireDict *
-psppire_var_sheet_get_dictionary (PsppireVarSheet *var_sheet)
-{
- return var_sheet->dict;
-}
-
-static void
-refresh_model (PsppireVarSheet *var_sheet)
-{
- pspp_sheet_view_set_model (PSPP_SHEET_VIEW (var_sheet), NULL);
-
- if (var_sheet->dict != NULL)
- {
- PsppireEmptyListStore *store;
- int n_rows;
-
- n_rows = (psppire_dict_get_var_cnt (var_sheet->dict)
- + var_sheet->may_create_vars);
- store = psppire_empty_list_store_new (n_rows);
- pspp_sheet_view_set_model (PSPP_SHEET_VIEW (var_sheet),
- GTK_TREE_MODEL (store));
- g_object_unref (store);
- }
-}
-
-static void
-on_var_changed (PsppireDict *dict, glong row,
- guint what, const struct variable *oldvar,
- PsppireVarSheet *var_sheet)
-{
- PsppireEmptyListStore *store;
-
- g_return_if_fail (dict == var_sheet->dict);
-
- store = PSPPIRE_EMPTY_LIST_STORE (pspp_sheet_view_get_model (
- PSPP_SHEET_VIEW (var_sheet)));
- g_return_if_fail (store != NULL);
-
- psppire_empty_list_store_row_changed (store, row);
-}
-
-static void
-on_var_inserted (PsppireDict *dict, glong row, PsppireVarSheet *var_sheet)
-{
- PsppireEmptyListStore *store;
- int n_rows;
-
- g_return_if_fail (dict == var_sheet->dict);
-
- store = PSPPIRE_EMPTY_LIST_STORE (pspp_sheet_view_get_model (
- PSPP_SHEET_VIEW (var_sheet)));
- g_return_if_fail (store != NULL);
-
- n_rows = (psppire_dict_get_var_cnt (var_sheet->dict)
- + var_sheet->may_create_vars);
- psppire_empty_list_store_set_n_rows (store, n_rows);
- psppire_empty_list_store_row_inserted (store, row);
-}
-
-static void
-on_var_deleted (PsppireDict *dict,
- const struct variable *var, int dict_idx, int case_idx,
- PsppireVarSheet *var_sheet)
-{
- PsppireEmptyListStore *store;
- int n_rows;
-
- g_return_if_fail (dict == var_sheet->dict);
-
- store = PSPPIRE_EMPTY_LIST_STORE (pspp_sheet_view_get_model (
- PSPP_SHEET_VIEW (var_sheet)));
- g_return_if_fail (store != NULL);
-
- n_rows = (psppire_dict_get_var_cnt (var_sheet->dict)
- + var_sheet->may_create_vars);
- psppire_empty_list_store_set_n_rows (store, n_rows);
- psppire_empty_list_store_row_deleted (store, dict_idx);
-}
-
-static void
-on_backend_changed (PsppireDict *dict, PsppireVarSheet *var_sheet)
-{
- g_return_if_fail (dict == var_sheet->dict);
- refresh_model (var_sheet);
-}
-
-void
-psppire_var_sheet_set_dictionary (PsppireVarSheet *var_sheet,
- PsppireDict *dict)
-{
- if (var_sheet->dict != NULL)
- {
- int i;
-
- for (i = 0; i < PSPPIRE_VAR_SHEET_N_SIGNALS; i++)
- {
- if (var_sheet->dict_signals[i])
- g_signal_handler_disconnect (var_sheet->dict,
- var_sheet->dict_signals[i]);
-
- var_sheet->dict_signals[i] = 0;
- }
-
- g_object_unref (var_sheet->dict);
- }
-
- var_sheet->dict = dict;
-
- if (dict != NULL)
- {
- g_object_ref (dict);
-
- var_sheet->dict_signals[PSPPIRE_VAR_SHEET_BACKEND_CHANGED]
- = g_signal_connect (dict, "backend-changed",
- G_CALLBACK (on_backend_changed), var_sheet);
-
- var_sheet->dict_signals[PSPPIRE_VAR_SHEET_VARIABLE_CHANGED]
- = g_signal_connect (dict, "variable-changed",
- G_CALLBACK (on_var_changed), var_sheet);
-
- var_sheet->dict_signals[PSPPIRE_VAR_SHEET_VARIABLE_DELETED]
- = g_signal_connect (dict, "variable-inserted",
- G_CALLBACK (on_var_inserted), var_sheet);
-
- var_sheet->dict_signals[PSPPIRE_VAR_SHEET_VARIABLE_INSERTED]
- = g_signal_connect (dict, "variable-deleted",
- G_CALLBACK (on_var_deleted), var_sheet);
- }
-
- refresh_model (var_sheet);
-}
-
-gboolean
-psppire_var_sheet_get_may_create_vars (PsppireVarSheet *var_sheet)
-{
- return var_sheet->may_create_vars;
-}
-
-void
-psppire_var_sheet_set_may_create_vars (PsppireVarSheet *var_sheet,
- gboolean may_create_vars)
-{
- if (var_sheet->may_create_vars != may_create_vars)
- {
- PsppireEmptyListStore *store;
- gint n_rows;
-
- var_sheet->may_create_vars = may_create_vars;
-
- store = PSPPIRE_EMPTY_LIST_STORE (pspp_sheet_view_get_model (
- PSPP_SHEET_VIEW (var_sheet)));
- g_return_if_fail (store != NULL);
-
- n_rows = (psppire_dict_get_var_cnt (var_sheet->dict)
- + var_sheet->may_create_vars);
- psppire_empty_list_store_set_n_rows (store, n_rows);
-
- if (may_create_vars)
- psppire_empty_list_store_row_inserted (store, n_rows - 1);
- else
- psppire_empty_list_store_row_deleted (store, n_rows);
-
- on_selection_changed (pspp_sheet_view_get_selection (
- PSPP_SHEET_VIEW (var_sheet)), NULL);
- }
-}
-
-gboolean
-psppire_var_sheet_get_may_delete_vars (PsppireVarSheet *var_sheet)
-{
- return var_sheet->may_delete_vars;
-}
-
-void
-psppire_var_sheet_set_may_delete_vars (PsppireVarSheet *var_sheet,
- gboolean may_delete_vars)
-{
- if (var_sheet->may_delete_vars != may_delete_vars)
- {
- var_sheet->may_delete_vars = may_delete_vars;
- on_selection_changed (pspp_sheet_view_get_selection (
- PSPP_SHEET_VIEW (var_sheet)), NULL);
- }
-}
-
-void
-psppire_var_sheet_goto_variable (PsppireVarSheet *var_sheet, int dict_index)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (var_sheet);
- GtkTreePath *path;
-
- path = gtk_tree_path_new_from_indices (dict_index, -1);
- pspp_sheet_view_scroll_to_cell (sheet_view, path, NULL, FALSE, 0.0, 0.0);
- pspp_sheet_view_set_cursor (sheet_view, path, NULL, FALSE);
- gtk_tree_path_free (path);
-}
-
-
+++ /dev/null
-/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2008, 2011, 2012 Free Software Foundation, Inc.
-
- 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/>. */
-
-#ifndef __PSPPIRE_VAR_SHEET_H__
-#define __PSPPIRE_VAR_SHEET_H__
-
-/* PsppireVarSheet is a PsppSheetView that displays the variables in a
- dictionary, one variable per row.
-
- PsppireDataSheet is usually a child of PsppireDataEditor in the widget
- hierarchy. Other widgets can also use it. */
-
-#include <gtk/gtk.h>
-#include "data/format.h"
-#include "ui/gui/pspp-sheet-view.h"
-
-
-G_BEGIN_DECLS
-
-#define PSPPIRE_TYPE_FMT_USE (psppire_fmt_use_get_type ())
-
-GType psppire_fmt_use_get_type (void) G_GNUC_CONST;
-\f
-#define PSPPIRE_VAR_SHEET_TYPE (psppire_var_sheet_get_type ())
-#define PSPPIRE_VAR_SHEET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PSPPIRE_VAR_SHEET_TYPE, PsppireVarSheet))
-#define PSPPIRE_VAR_SHEET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PSPPIRE_VAR_SHEET_TYPE, PsppireVarSheetClass))
-#define PSPPIRE_IS_VAR_SHEET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPPIRE_VAR_SHEET_TYPE))
-#define PSPPIRE_IS_VAR_SHEET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPPIRE_VAR_SHEET_TYPE))
-
-
-typedef struct _PsppireVarSheet PsppireVarSheet;
-typedef struct _PsppireVarSheetClass PsppireVarSheetClass;
-
-enum
-{
- PSPPIRE_VAR_SHEET_BACKEND_CHANGED,
- PSPPIRE_VAR_SHEET_VARIABLE_CHANGED,
- PSPPIRE_VAR_SHEET_VARIABLE_INSERTED,
- PSPPIRE_VAR_SHEET_VARIABLE_DELETED,
- PSPPIRE_VAR_SHEET_N_SIGNALS
- };
-
-struct _PsppireVarSheet
-{
- PsppSheetView parent;
-
- gboolean may_create_vars;
- gboolean may_delete_vars;
- enum fmt_use format_use;
-
- struct _PsppireDict *dict;
-
- gulong scroll_to_bottom_signal;
- gulong dict_signals[PSPPIRE_VAR_SHEET_N_SIGNALS];
-
- GtkWidget *container;
- gulong on_switch_page_handler;
-
- gboolean dispose_has_run;
-};
-
-struct _PsppireVarSheetClass
-{
- PsppSheetViewClass parent_class;
-};
-
-GType psppire_var_sheet_get_type (void);
-GtkWidget* psppire_var_sheet_new (void);
-
-struct _PsppireDict *psppire_var_sheet_get_dictionary (PsppireVarSheet *);
-void psppire_var_sheet_set_dictionary (PsppireVarSheet *,
- struct _PsppireDict *);
-
-gboolean psppire_var_sheet_get_may_create_vars (PsppireVarSheet *);
-void psppire_var_sheet_set_may_create_vars (PsppireVarSheet *, gboolean);
-
-gboolean psppire_var_sheet_get_may_delete_vars (PsppireVarSheet *);
-void psppire_var_sheet_set_may_delete_vars (PsppireVarSheet *, gboolean);
-
-void psppire_var_sheet_goto_variable (PsppireVarSheet *, int dict_index);
-void psppire_var_sheet_insert_variable (PsppireVarSheet *var_sheet);
-void psppire_var_sheet_clear_variables (PsppireVarSheet *var_sheet);
-
-
-G_END_DECLS
-
-#endif /* __PSPPIRE_VAR_SHEET_H__ */
--- /dev/null
+/* PSPPIRE - a graphical user interface for PSPP.
+ Copyright (C) 2016 Free Software Foundation
+
+ 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 <config.h>
+#include <gtk/gtk.h>
+
+#include <string.h>
+#include "value-variant.h"
+#include "data/value.h"
+
+
+enum
+ {
+ IDX_WIDTH,
+ IDX_DATA
+ };
+
+
+GVariant *
+value_variant_new (const union value *in, int width)
+{
+ GVariant *vv[2] = {NULL, NULL};
+ vv[IDX_WIDTH] = g_variant_new_int32 (width);
+
+ if (width == 0)
+ vv[IDX_DATA] = g_variant_new_double (in->f);
+ else if (width <= MAX_SHORT_STRING)
+ {
+ char xx[MAX_SHORT_STRING + 1];
+ memset (xx, '\0', MAX_SHORT_STRING + 1);
+ memcpy (xx, in->short_string, width);
+ vv[IDX_DATA] = g_variant_new_bytestring (xx);
+ }
+ else
+ {
+ gchar *q = xmalloc (width + 1);
+ memcpy (q, in->long_string, width);
+ q[width] = '\0';
+ vv[IDX_DATA] = g_variant_new_from_data (G_VARIANT_TYPE_BYTESTRING, q,
+ width + 1, FALSE, NULL, NULL);
+ }
+
+ return g_variant_new_tuple (vv, 2);
+}
+
+void
+value_destroy_from_variant (union value *val, GVariant *v)
+{
+ GVariant *vwidth = g_variant_get_child_value (v, IDX_WIDTH);
+ gint32 width = g_variant_get_int32 (vwidth);
+ g_variant_unref (vwidth);
+ value_destroy (val, width);
+}
+
+
+void
+value_variant_get (union value *val, GVariant *v)
+{
+ GVariant *vwidth = g_variant_get_child_value (v, IDX_WIDTH);
+ gint32 width = g_variant_get_int32 (vwidth);
+ g_variant_unref (vwidth);
+
+ GVariant *vdata = g_variant_get_child_value (v, IDX_DATA);
+
+ if (0 == width)
+ val->f = g_variant_get_double (vdata);
+ else
+ {
+ const gchar *data = g_variant_get_bytestring (vdata);
+ if (width <= MAX_SHORT_STRING)
+ memcpy (val->short_string, data, MAX_SHORT_STRING);
+ else
+ {
+ val->long_string = xmemdup (data, width);
+ }
+ }
+
+ g_variant_unref (vdata);
+}
--- /dev/null
+/* PSPPIRE - a graphical user interface for PSPP.
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+ 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/>. */
+
+#ifndef VALUE_VARIANT_H
+#define VALUE_VARIANT_H
+
+union value;
+
+GVariant *value_variant_new (const union value *in, int width);
+
+void value_variant_get (union value *val, GVariant *v);
+
+void value_destroy_from_variant (union value *val, GVariant *v);
+
+#endif
#include "widgets.h"
+#include "gettext.h"
#include "psppire-dialog.h"
#include "psppire-selector.h"
}
+static void
+tx_string_to_double (const GValue *src, GValue *dest)
+{
+ const gchar *str = g_value_get_string (src);
+ gdouble dble = g_strtod (str, NULL);
+ g_value_set_double (dest, dble);
+}
+
+
+static void
+tx_string_to_int (const GValue *src, GValue *dest)
+{
+ const gchar *str = g_value_get_string (src);
+ gint x = atoi (str);
+ g_value_set_int (dest, x);
+}
+
+static void
+enum_to_string (const GValue *src, GValue *dest)
+{
+ gint n = g_value_get_enum (src);
+ GType t = G_VALUE_TYPE (src);
+ GEnumClass *ec = g_type_class_ref (t);
+ GEnumValue *ev = g_enum_get_value (ec, n);
+
+ g_value_set_string (dest, gettext (ev->value_nick));
+}
+
+
+
+GType align_enum_type;
+GType measure_enum_type;
+GType role_enum_type;
+
+
+extern const GEnumValue align[];
+extern const GEnumValue measure[];
+extern const GEnumValue role[];
+
+
+
+static void
+preregister_misc (void)
+{
+ align_enum_type = g_enum_register_static ("PsppAlignment", align);
+ measure_enum_type = g_enum_register_static ("PsppMeasure", measure);
+ role_enum_type = g_enum_register_static ("PsppRole", role);
+
+ g_value_register_transform_func (G_TYPE_STRING, G_TYPE_DOUBLE, tx_string_to_double);
+ g_value_register_transform_func (G_TYPE_STRING, G_TYPE_INT, tx_string_to_int);
+
+ g_value_register_transform_func (measure_enum_type, G_TYPE_STRING, enum_to_string);
+ g_value_register_transform_func (align_enum_type, G_TYPE_STRING, enum_to_string);
+ g_value_register_transform_func (role_enum_type, G_TYPE_STRING, enum_to_string);
+}
+
/* Any custom widgets which are to be used in GtkBuilder ui files
need to be preregistered, otherwise GtkBuilder refuses to
psppire_means_layer_get_type ();
preregister_actions ();
+ preregister_misc ();
/* This seems to be necessary on Cygwin.
It ought not to be necessary. Having it here can't do any harm. */