From 698f289d1ecf1620aa5429599f2e76db23cff452 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 7 Jul 2011 08:09:17 -0700 Subject: [PATCH] gui: New type PsppireEmptyListStore. PsppireEmptyListStore is an GtkTreeModel implementation that has a client-specified number of rows and zero columns. It is a useful model for GtkTreeView or PsppSheetView when the client can easily synthesize cell data using a callback set with gtk_tree_view_column_set_cell_data_func(). In that situation, GtkListStore can be wasteful (because it uses a lot of memory to store what does not need to be stored) and situation-specific custom models require additional boilerplate. This commit also modified the text data import dialog code to use PsppireEmptyListStore. Future commits will add other users. --- src/ui/gui/automake.mk | 2 + src/ui/gui/psppire-empty-list-store.c | 369 ++++++++++++++++++++++++++ src/ui/gui/psppire-empty-list-store.h | 68 +++++ src/ui/gui/text-data-import-dialog.c | 348 ++++-------------------- 4 files changed, 491 insertions(+), 296 deletions(-) create mode 100644 src/ui/gui/psppire-empty-list-store.c create mode 100644 src/ui/gui/psppire-empty-list-store.h diff --git a/src/ui/gui/automake.mk b/src/ui/gui/automake.mk index 75ca28a713..4b2627885d 100644 --- a/src/ui/gui/automake.mk +++ b/src/ui/gui/automake.mk @@ -232,6 +232,8 @@ src_ui_gui_psppire_SOURCES = \ src/ui/gui/psppire-dict.h \ src/ui/gui/psppire-dictview.c \ src/ui/gui/psppire-dictview.h \ + src/ui/gui/psppire-empty-list-store.c \ + src/ui/gui/psppire-empty-list-store.h \ src/ui/gui/psppire-encoding-selector.c \ src/ui/gui/psppire-encoding-selector.h \ src/ui/gui/psppire-hbuttonbox.h \ diff --git a/src/ui/gui/psppire-empty-list-store.c b/src/ui/gui/psppire-empty-list-store.c new file mode 100644 index 0000000000..b7bc569def --- /dev/null +++ b/src/ui/gui/psppire-empty-list-store.c @@ -0,0 +1,369 @@ +/* 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 . */ + +#include + +#include "psppire-empty-list-store.h" + +static void psppire_empty_list_store_class_init (PsppireEmptyListStoreClass *); +static void psppire_empty_list_store_init (PsppireEmptyListStore *); + +/* GtkTreeModel interface. */ +static void gtk_tree_model_interface_init (GtkTreeModelIface *iface); +static GtkTreeModelFlags empty_list_store_get_flags (GtkTreeModel *tree_model); +static gint empty_list_store_get_n_columns (GtkTreeModel *tree_model); +static GType empty_list_store_get_column_type (GtkTreeModel *tree_model, + gint index_); +static gboolean empty_list_store_get_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreePath *path); +static GtkTreePath * empty_list_store_get_path (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static void empty_list_store_get_value (GtkTreeModel *tree_model, + GtkTreeIter *iter, + gint column, + GValue *value); +static gboolean empty_list_store_iter_next (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static gboolean empty_list_store_iter_children (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent); +static gboolean empty_list_store_iter_has_child (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static gint empty_list_store_iter_n_children (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static gboolean empty_list_store_iter_nth_child (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent, + gint n); +static gboolean empty_list_store_iter_parent (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *child); + +GType +psppire_empty_list_store_get_type (void) +{ + static GType type = 0; + if (!type) + { + static const GTypeInfo psppire_empty_list_store_info = + { + sizeof(PsppireEmptyListStoreClass), + NULL, /* base init */ + NULL, /* base finalize */ + (GClassInitFunc) psppire_empty_list_store_class_init, + NULL, /* class finalize */ + NULL, /* class data */ + sizeof(PsppireEmptyListStore), + 0, /* n_preallocs, ignored since 2.10 */ + (GInstanceInitFunc) psppire_empty_list_store_init, + NULL + }; + static const GInterfaceInfo gtk_tree_model_info = + { + (GInterfaceInitFunc) gtk_tree_model_interface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + type = g_type_register_static (G_TYPE_OBJECT, + "PsppireEmptyListStore", + &psppire_empty_list_store_info, 0); + g_type_add_interface_static (type, GTK_TYPE_TREE_MODEL, + >k_tree_model_info); + } + return type; +} + +enum + { + PROP_0, + PROP_N_ROWS + }; + +static void +psppire_empty_list_store_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PsppireEmptyListStore *obj = PSPPIRE_EMPTY_LIST_STORE (object); + + switch (prop_id) + { + case PROP_N_ROWS: + obj->n_rows = g_value_get_int (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +psppire_empty_list_store_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PsppireEmptyListStore *obj = PSPPIRE_EMPTY_LIST_STORE (object); + + switch (prop_id) + { + case PROP_N_ROWS: + g_value_set_int (value, obj->n_rows); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +psppire_empty_list_store_class_init (PsppireEmptyListStoreClass *class) +{ + GObjectClass *gobject_class; + gobject_class = G_OBJECT_CLASS (class); + + gobject_class->set_property = psppire_empty_list_store_set_property; + gobject_class->get_property = psppire_empty_list_store_get_property; + + g_object_class_install_property (gobject_class, + PROP_N_ROWS, + g_param_spec_int ("n-rows", + ("Number of rows"), + ("Number of rows in GtkTreeModel"), + 0, + G_MAXINT, + 0, + G_PARAM_READWRITE)); +} + +static void +psppire_empty_list_store_init (PsppireEmptyListStore *obj) +{ + obj->n_rows = 0; +} + +PsppireEmptyListStore * +psppire_empty_list_store_new (gint n_rows) +{ + return PSPPIRE_EMPTY_LIST_STORE (g_object_new (PSPPIRE_TYPE_EMPTY_LIST_STORE, + "n-rows", n_rows, + NULL)); +} + +gint +psppire_empty_list_store_get_n_rows (const PsppireEmptyListStore *obj) +{ + return obj->n_rows; +} + +void +psppire_empty_list_store_set_n_rows (PsppireEmptyListStore *obj, + gint n_rows) +{ + obj->n_rows = n_rows; +} + +void +psppire_empty_list_store_row_inserted (PsppireEmptyListStore *obj, + gint row) +{ + GtkTreeModel *tree_model = GTK_TREE_MODEL (obj); + GtkTreeIter iter; + GtkTreePath *path; + + path = gtk_tree_path_new_from_indices (row, -1); + gtk_tree_model_get_iter (tree_model, &iter, path); + gtk_tree_model_row_inserted (tree_model, path, &iter); + gtk_tree_path_free (path); +} + +void +psppire_empty_list_store_row_deleted (PsppireEmptyListStore *obj, + gint row) +{ + GtkTreeModel *tree_model = GTK_TREE_MODEL (obj); + GtkTreePath *path; + + path = gtk_tree_path_new_from_indices (row, -1); + gtk_tree_model_row_deleted (tree_model, path); + gtk_tree_path_free (path); +} + +/* GtkTreeModel interface. */ + +/* Random number used in 'stamp' member of GtkTreeIter. */ +#define TREE_MODEL_STAMP 0x10c44c13 + +static gboolean +empty_list_store_init_iter (GtkTreeModel *model, gint idx, GtkTreeIter *iter) +{ + const PsppireEmptyListStore *store = PSPPIRE_EMPTY_LIST_STORE (model); + + if (idx < 0 || idx >= store->n_rows) + { + iter->stamp = 0; + iter->user_data = GINT_TO_POINTER (-1); + return FALSE; + } + else + { + iter->stamp = TREE_MODEL_STAMP; + iter->user_data = GINT_TO_POINTER (idx); + return TRUE; + } +} + +static void +gtk_tree_model_interface_init (GtkTreeModelIface *iface) +{ + g_return_if_fail (iface != NULL); + + iface->get_flags = empty_list_store_get_flags; + iface->get_n_columns = empty_list_store_get_n_columns; + iface->get_column_type = empty_list_store_get_column_type; + iface->get_iter = empty_list_store_get_iter; + iface->get_path = empty_list_store_get_path; + iface->get_value = empty_list_store_get_value; + iface->iter_next = empty_list_store_iter_next; + iface->iter_children = empty_list_store_iter_children; + iface->iter_has_child = empty_list_store_iter_has_child; + iface->iter_n_children = empty_list_store_iter_n_children; + iface->iter_nth_child = empty_list_store_iter_nth_child; + iface->iter_parent = empty_list_store_iter_parent; +} + +static GtkTreeModelFlags +empty_list_store_get_flags (GtkTreeModel *tree_model G_GNUC_UNUSED) +{ + return GTK_TREE_MODEL_LIST_ONLY; +} + +static gint +empty_list_store_get_n_columns (GtkTreeModel *tree_model G_GNUC_UNUSED) +{ + return 0; +} + +static GType +empty_list_store_get_column_type (GtkTreeModel *tree_model, + gint index_) +{ + g_return_val_if_reached (G_TYPE_NONE); +} + +static gboolean +empty_list_store_get_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreePath *path) +{ + gint *indices, depth; + + g_return_val_if_fail (path, FALSE); + + indices = gtk_tree_path_get_indices (path); + depth = gtk_tree_path_get_depth (path); + + g_return_val_if_fail (depth == 1, FALSE); + + return empty_list_store_init_iter (tree_model, indices[0], iter); +} + +static GtkTreePath * +empty_list_store_get_path (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + GtkTreePath *path; + + g_return_val_if_fail (iter->stamp == TREE_MODEL_STAMP, FALSE); + + path = gtk_tree_path_new (); + gtk_tree_path_append_index (path, GPOINTER_TO_INT (iter->user_data)); + + return path; +} + +static void +empty_list_store_get_value (GtkTreeModel *tree_model, + GtkTreeIter *iter, + gint column, + GValue *value) +{ + g_return_if_reached (); +} + +static gboolean +empty_list_store_iter_next (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + gint idx; + + g_return_val_if_fail (iter->stamp == TREE_MODEL_STAMP, FALSE); + + idx = GPOINTER_TO_INT (iter->user_data); + return empty_list_store_init_iter (tree_model, idx + (idx >= 0), iter); +} + +static gboolean +empty_list_store_iter_children (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent) +{ + return FALSE; +} + +static gboolean +empty_list_store_iter_has_child (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + return FALSE; +} + +static gint +empty_list_store_iter_n_children (GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + return iter == NULL ? PSPPIRE_EMPTY_LIST_STORE (tree_model)->n_rows : 0; +} + +static gboolean +empty_list_store_iter_nth_child (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent, + gint n) +{ + g_return_val_if_fail (parent == NULL, FALSE); + + return empty_list_store_init_iter (tree_model, n, iter); +} + +static gboolean +empty_list_store_iter_parent (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *child) +{ + return FALSE; +} + +gint +empty_list_store_iter_to_row (const GtkTreeIter *iter) +{ + g_return_val_if_fail (iter->stamp == TREE_MODEL_STAMP, 0); + return GPOINTER_TO_INT (iter->user_data); +} diff --git a/src/ui/gui/psppire-empty-list-store.h b/src/ui/gui/psppire-empty-list-store.h new file mode 100644 index 0000000000..ae6d36c483 --- /dev/null +++ b/src/ui/gui/psppire-empty-list-store.h @@ -0,0 +1,68 @@ +/* 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 . */ + +#ifndef PSPPIRE_EMPTY_LIST_STORE_H +#define PSPPIRE_EMPTY_LIST_STORE_H 1 + +/* PsppireEmptyListStore is an GtkTreeModel implementation that has a + client-specified number of rows and zero columns. It is a useful model for + GtkTreeView or PsppSheetView when the client can easily synthesize cell data + using a callback set with gtk_tree_view_column_set_cell_data_func(). In + that situation, GtkListStore can be wasteful (because it uses a lot of + memory to store what does not need to be stored) and situation-specific + custom models require additional boilerplate. */ + +#include +#include + +G_BEGIN_DECLS + +#define PSPPIRE_TYPE_EMPTY_LIST_STORE (psppire_empty_list_store_get_type()) +#define PSPPIRE_EMPTY_LIST_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),PSPPIRE_TYPE_EMPTY_LIST_STORE,PsppireEmptyListStore)) +#define PSPPIRE_EMPTY_LIST_STORE_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class),PSPPIRE_TYPE_EMPTY_LIST_STORE,PsppireEmptyListStoreClass)) +#define PSPPIRE_IS_EMPTY_LIST_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),PSPPIRE_TYPE_EMPTY_LIST_STORE)) +#define PSPPIRE_IS_EMPTY_LIST_STORE_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class),PSPPIRE_TYPE_EMPTY_LIST_STORE)) +#define PSPPIRE_EMPTY_LIST_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),PSPPIRE_TYPE_EMPTY_LIST_STORE,PsppireEmptyListStoreClass)) + +typedef struct _PsppireEmptyListStore PsppireEmptyListStore; +typedef struct _PsppireEmptyListStoreClass PsppireEmptyListStoreClass; + +struct _PsppireEmptyListStore { + GObject parent; + gint n_rows; +}; + +struct _PsppireEmptyListStoreClass { + GObjectClass parent_class; +}; + +GType psppire_empty_list_store_get_type (void) G_GNUC_CONST; +PsppireEmptyListStore* psppire_empty_list_store_new (gint n_rows); + +gint psppire_empty_list_store_get_n_rows (const PsppireEmptyListStore *); +void psppire_empty_list_store_set_n_rows (PsppireEmptyListStore *, + gint n_rows); + +void psppire_empty_list_store_row_inserted (PsppireEmptyListStore *, + gint row); +void psppire_empty_list_store_row_deleted (PsppireEmptyListStore *, + gint row); + +gint empty_list_store_iter_to_row (const GtkTreeIter *); + +G_END_DECLS + +#endif /* PSPPIRE_EMPTY_LIST_STORE_H */ diff --git a/src/ui/gui/text-data-import-dialog.c b/src/ui/gui/text-data-import-dialog.c index 7c9603d69d..10dc626609 100644 --- a/src/ui/gui/text-data-import-dialog.c +++ b/src/ui/gui/text-data-import-dialog.c @@ -41,33 +41,20 @@ #include "ui/gui/builder-wrapper.h" #include "ui/gui/psppire-data-window.h" #include "ui/gui/psppire-dialog.h" +#include "ui/gui/psppire-empty-list-store.h" #include "ui/gui/psppire-var-sheet.h" #include "ui/gui/psppire-var-store.h" #include "ui/gui/psppire-scanf.h" #include "ui/syntax-gen.h" #include "gl/error.h" +#include "gl/intprops.h" #include "gl/xalloc.h" #include "gettext.h" #define _(msgid) gettext (msgid) #define N_(msgid) msgid - -/* TextImportModel, a GtkTreeModel used by the text data import - dialog. */ -enum - { - TEXT_IMPORT_MODEL_COLUMN_LINE_NUMBER, /* 1-based line number in file */ - TEXT_IMPORT_MODEL_COLUMN_LINE, /* The line from the file. */ - }; -typedef struct TextImportModel TextImportModel; -typedef struct TextImportModelClass TextImportModelClass; - -TextImportModel *text_import_model_new (struct string *lines, size_t line_cnt, - size_t first_line); -gint text_import_model_iter_to_row (const GtkTreeIter *); - struct import_assistant; /* The file to be imported. */ @@ -898,6 +885,23 @@ reset_first_line_page (struct import_assistant *ia) set_first_line (ia); } +static void +render_line (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + gpointer data) +{ + gint row = empty_list_store_iter_to_row (iter); + struct string *lines; + + lines = g_object_get_data (G_OBJECT (tree_model), "lines"); + g_return_if_fail (lines != NULL); + + g_object_set (cell, "text", ds_cstr (&lines[row]), NULL); +} + + /* Creates and returns a tree view that contains each of the lines in IA's file as a row. */ static GtkTreeView * @@ -912,12 +916,10 @@ create_lines_tree_view (GtkContainer *parent, struct import_assistant *ia) make_tree_view (ia, 0, &tree_view); - column = gtk_tree_view_column_new_with_attributes - ( - title, ia->asst.fixed_renderer, - "text", TEXT_IMPORT_MODEL_COLUMN_LINE, - (void *) NULL - ); + column = gtk_tree_view_column_new_with_attributes ( + title, ia->asst.fixed_renderer, (void *) NULL); + gtk_tree_view_column_set_cell_data_func (column, ia->asst.fixed_renderer, + render_line, NULL, NULL); gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED); max_line_length = 0; @@ -1537,7 +1539,7 @@ render_input_cell (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column), "column-number")); - row = text_import_model_iter_to_row (iter) + ia->first_line.skip_lines; + row = empty_list_store_iter_to_row (iter) + ia->first_line.skip_lines; field = ia->separators.columns[column].contents[row]; if (field.string != NULL) { @@ -1851,7 +1853,7 @@ render_output_cell (GtkTreeViewColumn *tree_column, bool ok; ok = parse_field (ia, - (text_import_model_iter_to_row (iter) + (empty_list_store_iter_to_row (iter) + ia->first_line.skip_lines), GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_column), "column-number")), @@ -1935,7 +1937,7 @@ get_tooltip_location (GtkWidget *widget, gint wx, gint wy, if (!ok) return FALSE; - *row = text_import_model_iter_to_row (&iter) + ia->first_line.skip_lines; + *row = empty_list_store_iter_to_row (&iter) + ia->first_line.skip_lines; return TRUE; } @@ -1947,14 +1949,33 @@ make_tree_view (const struct import_assistant *ia, GtkTreeModel *model; *tree_view = GTK_TREE_VIEW (gtk_tree_view_new ()); - model = GTK_TREE_MODEL (text_import_model_new ( - ia->file.lines + first_line, - ia->file.line_cnt - first_line, first_line)); + model = GTK_TREE_MODEL (psppire_empty_list_store_new ( + ia->file.line_cnt - first_line)); + g_object_set_data (G_OBJECT (model), "lines", ia->file.lines + first_line); + g_object_set_data (G_OBJECT (model), "first-line", + GINT_TO_POINTER (first_line)); gtk_tree_view_set_model (*tree_view, model); add_line_number_column (ia, *tree_view); } +static void +render_line_number (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + gpointer data) +{ + gint row = empty_list_store_iter_to_row (iter); + char s[INT_BUFSIZE_BOUND (int)]; + int first_line; + + first_line = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree_model), + "first-line")); + sprintf (s, "%d", first_line + row); + g_object_set (cell, "text", s, NULL); +} + static void add_line_number_column (const struct import_assistant *ia, GtkTreeView *treeview) @@ -1962,12 +1983,13 @@ add_line_number_column (const struct import_assistant *ia, GtkTreeViewColumn *column; column = gtk_tree_view_column_new_with_attributes ( - _("Line"), ia->asst.prop_renderer, - "text", TEXT_IMPORT_MODEL_COLUMN_LINE_NUMBER, - (void *) NULL); + _("Line"), ia->asst.prop_renderer, (void *) NULL); gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_fixed_width ( column, get_monospace_width (treeview, ia->asst.prop_renderer, 5)); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_column_set_cell_data_func (column, ia->asst.prop_renderer, + render_line_number, NULL, NULL); gtk_tree_view_append_column (treeview, column); } @@ -2083,272 +2105,6 @@ escape_underscores (const char *in) return out; } - -/* TextImportModel, a GtkTreeModel implementation used by some - pages of the assistant. */ - -#define G_TYPE_TEXT_IMPORT_MODEL (text_import_model_get_type ()) -#define TEXT_IMPORT_MODEL(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), G_TYPE_TEXT_IMPORT_MODEL, TextImportModel)) -#define TEXT_IMPORT_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_TYPE_TEXT_IMPORT_MODEL, TextImportModelClass)) -#define IS_TEXT_IMPORT_MODEL(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), G_TYPE_TEXT_IMPORT_MODEL)) -#define IS_TEXT_IMPORT_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), G_TYPE_TEXT_IMPORT_MODEL)) -#define TEXT_IMPORT_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_TEXT_IMPORT_MODEL, TextImportModelClass)) - -/* Random number used in 'stamp' member of GtkTreeIter. */ -#define TREE_MODEL_STAMP 0x7efd67d3 - -struct TextImportModel -{ - GObject parent; - struct string *lines; - size_t line_cnt; - size_t first_line; -}; - -struct TextImportModelClass -{ - GObjectClass parent_class; -}; - -GType text_import_model_get_type (void); -static void text_import_model_tree_model_init (gpointer iface, gpointer data); - -GType -text_import_model_get_type (void) -{ - static GType object_type = 0; - - if (!object_type) - { - static const GTypeInfo object_info = { - sizeof (TextImportModelClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - NULL, /* class_init */ - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (TextImportModel), - 0, /* n_preallocs */ - NULL, /* instance_init */ - }; - - static const GInterfaceInfo tree_model_info = { - text_import_model_tree_model_init, - NULL, - NULL - }; - - object_type = g_type_register_static (G_TYPE_OBJECT, - "TextImportModel", - &object_info, 0); - - g_type_add_interface_static (object_type, GTK_TYPE_TREE_MODEL, - &tree_model_info); - - - } - - return object_type; -} - - -/* Creates and returns a new TextImportModel that contains the - LINE_CNT lines in LINES. The lines before FIRST_LINE in LINES - are not part of the model, but they are included in the line - numbers in the TEXT_IMPORT_MODEL_COLUMN_LINE_NUMBER column. - - The caller retains responsibility for freeing LINES and must - ensure that its lifetime and that of the strings that it - contains exceeds that of the TextImportModel. */ -TextImportModel * -text_import_model_new (struct string *lines, size_t line_cnt, - size_t first_line) -{ - TextImportModel *new_text_import_model - = g_object_new (G_TYPE_TEXT_IMPORT_MODEL, NULL); - new_text_import_model->lines = lines; - new_text_import_model->line_cnt = line_cnt; - new_text_import_model->first_line = first_line; - return new_text_import_model; -} - - -static gboolean -tree_model_iter_has_child (GtkTreeModel *tree_model, - GtkTreeIter *iter) -{ - return FALSE; -} - -static gboolean -tree_model_iter_parent (GtkTreeModel *tree_model, - GtkTreeIter *iter, - GtkTreeIter *child) -{ - return TRUE; -} - -static GtkTreeModelFlags -tree_model_get_flags (GtkTreeModel *model) -{ - g_return_val_if_fail (IS_TEXT_IMPORT_MODEL (model), (GtkTreeModelFlags) 0); - - return GTK_TREE_MODEL_LIST_ONLY | GTK_TREE_MODEL_ITERS_PERSIST; -} - - -static gint -tree_model_n_columns (GtkTreeModel *model) -{ - return 2; -} - -static GType -tree_model_column_type (GtkTreeModel *model, gint index) -{ - return (index == TEXT_IMPORT_MODEL_COLUMN_LINE_NUMBER ? G_TYPE_INT - : index == TEXT_IMPORT_MODEL_COLUMN_LINE ? G_TYPE_STRING - : -1); -} - -static gboolean -init_iter (TextImportModel *list, gint idx, GtkTreeIter *iter) -{ - if (idx < 0 || idx >= list->line_cnt) - { - iter->stamp = 0; - iter->user_data = GINT_TO_POINTER (-1); - return FALSE; - } - else - { - iter->stamp = TREE_MODEL_STAMP; - iter->user_data = GINT_TO_POINTER (idx); - return TRUE; - } -} - -static gboolean -tree_model_get_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreePath *path) -{ - gint *indices, depth; - - TextImportModel *list = TEXT_IMPORT_MODEL (model); - - g_return_val_if_fail (path, FALSE); - - indices = gtk_tree_path_get_indices (path); - depth = gtk_tree_path_get_depth (path); - - g_return_val_if_fail (depth == 1, FALSE); - - return init_iter (list, indices[0], iter); -} - - -static gboolean -tree_model_iter_next (GtkTreeModel *model, GtkTreeIter *iter) -{ - TextImportModel *list = TEXT_IMPORT_MODEL (model); - gint idx; - - assert (iter->stamp == TREE_MODEL_STAMP); - - idx = GPOINTER_TO_INT (iter->user_data); - return init_iter (list, idx == -1 ? -1 : idx + 1, iter); -} - -static GtkTreePath * -tree_model_get_path (GtkTreeModel *model, GtkTreeIter *iter) -{ - GtkTreePath *path; - - g_return_val_if_fail (iter->stamp == TREE_MODEL_STAMP, FALSE); - - path = gtk_tree_path_new (); - gtk_tree_path_append_index (path, GPOINTER_TO_INT (iter->user_data)); - - return path; -} - -static void -tree_model_get_value (GtkTreeModel *model, GtkTreeIter *iter, - gint column, GValue *value) -{ - TextImportModel *list = TEXT_IMPORT_MODEL (model); - gint idx; - - g_return_if_fail (iter->stamp == TREE_MODEL_STAMP); - - idx = GPOINTER_TO_INT (iter->user_data); - assert (idx >= 0 && idx < list->line_cnt); - - if (column == 0) - { - g_value_init (value, G_TYPE_INT); - g_value_set_int (value, idx + list->first_line + 1); - } - else - { - g_value_init (value, G_TYPE_STRING); - g_value_set_static_string (value, ds_cstr (&list->lines[idx])); - } -} - -static gboolean -tree_model_iter_children (GtkTreeModel *tree_model, - GtkTreeIter *iter, - GtkTreeIter *parent) -{ - return FALSE; -} - -static gint -tree_model_n_children (GtkTreeModel *model, GtkTreeIter *iter) -{ - TextImportModel *list = TEXT_IMPORT_MODEL (model); - - return iter == NULL ? list->line_cnt : 0; -} - -static gboolean -tree_model_nth_child (GtkTreeModel *model, GtkTreeIter *iter, - GtkTreeIter *parent, gint n) -{ - TextImportModel *list = TEXT_IMPORT_MODEL (model); - g_return_val_if_fail (IS_TEXT_IMPORT_MODEL (model), FALSE); - - if (parent) - return FALSE; - return init_iter (list, n, iter); -} - -static void -text_import_model_tree_model_init (gpointer iface_, gpointer data UNUSED) -{ - GtkTreeModelIface *iface = (GtkTreeModelIface *) iface_; - - iface->get_flags = tree_model_get_flags; - iface->get_n_columns = tree_model_n_columns; - iface->get_column_type = tree_model_column_type; - iface->get_iter = tree_model_get_iter; - iface->iter_next = tree_model_iter_next; - iface->get_path = tree_model_get_path; - iface->get_value = tree_model_get_value; - - iface->iter_children = tree_model_iter_children; - iface->iter_has_child = tree_model_iter_has_child; - iface->iter_n_children = tree_model_n_children; - iface->iter_nth_child = tree_model_nth_child; - iface->iter_parent = tree_model_iter_parent; -} - -gint -text_import_model_iter_to_row (const GtkTreeIter *iter) -{ - assert (iter->stamp == TREE_MODEL_STAMP); - return GPOINTER_TO_INT (iter->user_data); -} /* Increments the "watch cursor" level, setting the cursor for the assistant window to a watch face to indicate to the user -- 2.30.2