diff options
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | docs/reference/ChangeLog | 5 | ||||
-rw-r--r-- | docs/reference/pygtk-pygtkgenerictreemodel.xml | 69 | ||||
-rw-r--r-- | examples/Makefile.am | 1 | ||||
-rw-r--r-- | examples/gtk/customtreemodel.py | 177 | ||||
-rw-r--r-- | gtk/gtk-extrafuncs.defs | 18 | ||||
-rw-r--r-- | gtk/pygtktreemodel.c | 40 | ||||
-rw-r--r-- | gtk/pygtktreemodel.h | 6 |
8 files changed, 327 insertions, 1 deletions
@@ -1,3 +1,15 @@ +2007-07-30 Paul Pogonyshev <pogonyshev@gmx.net> + + reviewed by: Johan, Fix bug #388754 + + * examples/gtk/customtreemodel.py: Add usage example. + + * gtk/gtk-extrafuncs.defs (get_user_data, create_tree_iter): New + methods of `gtk.GenericTreeModel'. + + * gtk/pygtktreemodel.c (pygtk_generic_tree_model_get_user_data) + (pygtk_generic_tree_model_create_tree_iter): New functions. + 2007-07-28 Gian Mario Tagliaretti <gianmt@gnome.org> reviewed by: gjc, Fix bug #461245 diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog index 3fb6257f..3d9e6262 100644 --- a/docs/reference/ChangeLog +++ b/docs/reference/ChangeLog @@ -1,3 +1,8 @@ +2007-07-30 Paul Pogonyshev <pogonyshev@gmx.net> + + * pygtk-pygtkgenerictreemodel.xml: Document new create_tree_iter() + and get_user_data(). + 2007-07-29 Gian Mario Tagliaretti <gianmt@gnome.org> * pygtk-gtkicontheme.xml: Update with 2.12 API. diff --git a/docs/reference/pygtk-pygtkgenerictreemodel.xml b/docs/reference/pygtk-pygtkgenerictreemodel.xml index 54677206..455a28e9 100644 --- a/docs/reference/pygtk-pygtkgenerictreemodel.xml +++ b/docs/reference/pygtk-pygtkgenerictreemodel.xml @@ -30,6 +30,14 @@ linkend="constructor-gtkgenerictreemodel">gtk.GenericTreeModel</link></methodnam <methodname><link linkend="method-gtkgenerictreemodel--iter-is-valid">iter_is_valid</link></methodname> <methodparam><parameter role="keyword">iter</parameter></methodparam> </methodsynopsis> + <methodsynopsis language="python"> + <methodname><link linkend="method-gtkgenerictreemodel--get-user-data">get_user_data</link></methodname> + <methodparam><parameter role="keyword">iter</parameter></methodparam> + </methodsynopsis> + <methodsynopsis language="python"> + <methodname><link linkend="method-gtkgenerictreemodel--create-tree-iter">create_tree_iter</link></methodname> + <methodparam><parameter role="keyword">user_data</parameter></methodparam> + </methodsynopsis> </classsynopsis> </refsect1> @@ -274,6 +282,67 @@ model.</para> </refsect2> + <refsect2 id="method-gtkgenerictreemodel--get-user-data"> + <title>gtk.GenericTreeModel.get_user_data</title> + + <programlisting><methodsynopsis language="python"> + <methodname>get_user_data</methodname> + <methodparam><parameter + role="keyword">iter</parameter></methodparam> + </methodsynopsis></programlisting> + <variablelist> + <varlistentry> + <term><parameter role="keyword">iter</parameter> :</term> + <listitem><simpara>a <link + linkend="class-gtktreeiter"><classname>gtk.TreeIter</classname></link> + created by this tree model.</simpara></listitem> + </varlistentry> + <varlistentry> + <term><emphasis>Returns</emphasis> :</term> + <listitem><simpara>Python object reference that is wrapped by this + <classname>gtk.TreeIter</classname>.</simpara></listitem> + </varlistentry> + </variablelist> + + <warning> + <para>This method should be treated as protected. It should only + be used by derived classes.</para> + </warning> + + <para><classname>gtk.GenericTreeModel</classname> transparently wraps arbitrary Python objects to instances of <link linkend="class-gtktreeiter"><classname>gtk.TreeIter</classname></link>. E.g. you return anything from <methodname>on_get_iter</methodname> and the model wraps the value, so <methodname>get_iter</methodname> method returns a <classname>gtk.TreeIter</classname>. This method allows to retrieve the Python object used to construct given iterator.</para> + + </refsect2> + + <refsect2 id="method-gtkgenerictreemodel--create-tree-iter"> + <title>gtk.GenericTreeModel.create_tree_iter</title> + + <programlisting><methodsynopsis language="python"> + <methodname>create_tree_iter</methodname> + <methodparam><parameter + role="keyword">user_data</parameter></methodparam> + </methodsynopsis></programlisting> + <variablelist> + <varlistentry> + <term><parameter role="keyword">user_data</parameter> :</term> + <listitem><simpara>a Python object, the same you would return from + e.g. <methodname>on_get_iter</methodname>.</simpara></listitem> + </varlistentry> + <varlistentry> + <term><emphasis>Returns</emphasis> :</term> + <listitem><simpara>a <link + linkend="class-gtktreeiter"><classname>gtk.TreeIter</classname></link>.</simpara></listitem> + </varlistentry> + </variablelist> + + <warning> + <para>This method should be treated as protected. It should only + be used by derived classes.</para> + </warning> + + <para><classname>gtk.GenericTreeModel</classname> transparently wraps arbitrary Python objects to instances of <link linkend="class-gtktreeiter"><classname>gtk.TreeIter</classname></link>. E.g. you return anything from <methodname>on_get_iter</methodname> and the model wraps the value, so <methodname>get_iter</methodname> method returns a <classname>gtk.TreeIter</classname>. This method allows you to perform this wrapping explicitly, not just from a predefined set of methods.</para> + + </refsect2> + </refsect1> </refentry> diff --git a/examples/Makefile.am b/examples/Makefile.am index 2407b296..e53dbbd3 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -20,6 +20,7 @@ EXTRA_DIST = \ gobject/properties.py \ gobject/signal.py \ gtk/bin.py \ + gtk/customtreemodel.py \ gtk/filechooser.py \ gtk/scrollable.py \ gtk/sizegroup.py \ diff --git a/examples/gtk/customtreemodel.py b/examples/gtk/customtreemodel.py new file mode 100644 index 00000000..27335dce --- /dev/null +++ b/examples/gtk/customtreemodel.py @@ -0,0 +1,177 @@ +#! /usr/bin/env python + +import sys +import weakref + +import pango +import gtk + + +class SimpleListTreeModel(gtk.GenericTreeModel): + + def on_get_flags(self): + return gtk.TREE_MODEL_LIST_ONLY + + def __init__(self, *values): + gtk.GenericTreeModel.__init__(self) + self.__values = list(values) + + self.props.leak_references = False + + # This is only needed to make the model gc-safe, since + # leak_references is False. + self.__iters = range(0, len(values)) + + def on_get_n_columns(self): + return 0 + + def on_get_column_type(self, index): + raise NotImplementedError + + def on_get_value(self, row, column): + raise NotImplementedError + + def on_get_iter(self, path): + return self.__iters[path[0]] + + def on_get_path(self, row): + return(row,) + + def on_iter_parent(self, row): + return None + + def on_iter_next(self, row): + if row + 1 < len(self.__values): + return self.__iters[row + 1] + else: + return None + + def on_iter_has_child(self, row): + return False + + def on_iter_children(self, row): + if row is None: + return self.__iters[0] + else: + return None + + def on_iter_n_children(self, row): + if row is None: + return len(self.__values) + else: + return 0 + + def on_iter_nth_child(self, parent, n): + if parent: + return None + else: + return self.__iters[n] + + + def __len__ (self): + return len(self.__values) + + def __getitem__ (self, key): + return self.__values[self.get_user_data(key)] + + def __iter__ (self): + return iter(self.__values) + + def __contains__ (self, value): + return value in self.__values + + + def insert(self, index_or_iter, new_value): + if isinstance(index_or_iter, gtk.TreeIter): + index_or_iter = self.get_user_data(index_or_iter) + + self.__values.insert(index_or_iter, new_value) + self.__iters.append(len(self.__iters)) + + titer = self.create_tree_iter(self.__iters[index_or_iter]) + self.row_inserted(self.get_path(titer), titer) + + +class Food(object): + + def __init__(self, name, description=None): + self.name = name + self.description = description + + def set_to_text_renderer(column, cell, model, iter): + value = model[iter] + + cell.props.text = value.name + + if value.description is None: + cell.props.weight = pango.WEIGHT_BOLD + else: + cell.props.weight = pango.WEIGHT_NORMAL + + set_to_text_renderer = staticmethod(set_to_text_renderer) + + +def generate_values(): + yield Food('Fruits') + yield Food('Apple', 'Round and red. Or green. Or yellow.') + yield Food('Orange', 'Juicy') + yield Food('Vegetables') + yield Food('Tomato', 'Red and juicy.') + yield Food('Cucumber', 'Long and hard.') + +def insert_item(*ignored): + model, titer = tree_view.get_selection().get_selected() + + if titer is None or model[titer].description is None: + dialog = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_OK, + message_format='Please select something. And not a header!') + dialog.run() + dialog.destroy() + else: + model.insert(titer, Food('Random name', 'Some random, but useful description.')) + +def show_description(*ignored): + model, titer = tree_view.get_selection().get_selected() + + if titer is None or model[titer].description is None: + dialog = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_OK, + message_format='Please select something. And not a header!') + else: + dialog = gtk.MessageDialog(buttons=gtk.BUTTONS_OK, + message_format=model[titer].description) + + dialog.run() + dialog.destroy() + +window = gtk.Window() +tree_model = SimpleListTreeModel(*generate_values()) +tree_view = gtk.TreeView(tree_model) +scrolled_window = gtk.ScrolledWindow() +vertical_box = gtk.VBox(False, 6) +button_box = gtk.HButtonBox() +insert = gtk.Button('Insert') +description = gtk.Button('Show Description') + +scrolled_window.add(tree_view) +vertical_box.pack_start(scrolled_window) +vertical_box.pack_start(button_box, False, False) +button_box.pack_start(insert) +button_box.pack_start(description) +window.add(vertical_box) + +tree_view.set_headers_visible(False) + +text_renderer = gtk.CellRendererText() +column = gtk.TreeViewColumn(None, text_renderer) + +column.set_cell_data_func(text_renderer, Food.set_to_text_renderer) +tree_view.append_column(column) + +insert.connect('clicked', insert_item) +description.connect('clicked', show_description) +window.connect('destroy', lambda window: gtk.main_quit()) + +window.resize(400, 500) +window.show_all() + +gtk.main() diff --git a/gtk/gtk-extrafuncs.defs b/gtk/gtk-extrafuncs.defs index af690ef8..29c71f0c 100644 --- a/gtk/gtk-extrafuncs.defs +++ b/gtk/gtk-extrafuncs.defs @@ -88,6 +88,24 @@ ) ) +(define-method get_user_data + (of-object "PyGtkGenericTreeModel") + (c-name "pygtk_generic_tree_model_get_user_data") + (return-type "PyObject*") + (parameters + '("GtkTreeIter*" "iter") + ) +) + +(define-method create_tree_iter + (of-object "PyGtkGenericTreeModel") + (c-name "pygtk_generic_tree_model_create_tree_iter") + (return-type "GtkTreeIter") + (parameters + '("PyObject*" "user_data") + ) +) + ;; PyGtkGenericCellRenderer (define-object GenericCellRenderer diff --git a/gtk/pygtktreemodel.c b/gtk/pygtktreemodel.c index a3f85805..f908c37b 100644 --- a/gtk/pygtktreemodel.c +++ b/gtk/pygtktreemodel.c @@ -24,7 +24,6 @@ #endif #include "pygtktreemodel.h" -#include <Python.h> #include "pygtk-private.h" /* define this to print out debug messages */ @@ -801,3 +800,42 @@ pygtk_generic_tree_model_iter_is_valid(PyGtkGenericTreeModel *tree_model, return VALID_ITER(iter, tree_model); } + +PyObject * +pygtk_generic_tree_model_get_user_data(PyGtkGenericTreeModel *tree_model, + GtkTreeIter *iter) +{ + g_return_val_if_fail(tree_model != NULL, NULL); + + if (VALID_ITER(iter, tree_model)) { + /* Py_INCREF and NULL checking is done at _wrap_*() level. */ + return iter->user_data; + } + else { + g_warning("iter is not valid for the tree model"); + return NULL; + } +} + +GtkTreeIter +pygtk_generic_tree_model_create_tree_iter(PyGtkGenericTreeModel *tree_model, + PyObject *user_data) +{ + GtkTreeIter iter; + + if (tree_model != NULL) { + iter.user_data = user_data; + iter.stamp = PYGTK_GENERIC_TREE_MODEL(tree_model)->stamp; + + /* Otherwise, caller is supposed to hold a reference somewhere. */ + if (PYGTK_GENERIC_TREE_MODEL(tree_model)->leak_references) + Py_INCREF(user_data); + } + else { + /* FIXME: I guess this is still not enough. */ + iter.user_data = NULL; + iter.stamp = 0; + } + + return iter; +} diff --git a/gtk/pygtktreemodel.h b/gtk/pygtktreemodel.h index 703eefb0..2412c4bc 100644 --- a/gtk/pygtktreemodel.h +++ b/gtk/pygtktreemodel.h @@ -20,6 +20,8 @@ * USA */ +#include <Python.h> + #include <gtk/gtktreemodel.h> #define PYGTK_TYPE_GENERIC_TREE_MODEL (pygtk_generic_tree_model_get_type()) @@ -48,3 +50,7 @@ PyGtkGenericTreeModel * pygtk_generic_tree_model_new (void); void pygtk_generic_tree_model_invalidate_iters(PyGtkGenericTreeModel *); gboolean pygtk_generic_tree_model_iter_is_valid(PyGtkGenericTreeModel *, GtkTreeIter *); +PyObject * pygtk_generic_tree_model_get_user_data(PyGtkGenericTreeModel *, + GtkTreeIter *); +GtkTreeIter pygtk_generic_tree_model_create_tree_iter(PyGtkGenericTreeModel *, + PyObject *); |