@c -----------------------------------------------------------------------------
@c File     : gtk-text-view.texi
@c License  : GNU General Public License (GPL)
@c Language : English
@c Author   : Dieter Kaiser
@c Date     : 08.07.2012
@c Revision : 18.10.2013
@c
@c Copyright (C) 2012, 2013 by Dieter Kaiser
@c -----------------------------------------------------------------------------

@menu
* Overview::
* GtkListStore and GtkTreeStore::
* Creating a Tree View::
* Mapping Data to the Screen::
* Selections Double-Clicks and Context Menus::
* Sorting::
* Editable Cells::
* Miscellaneous::
* Drag and Drop::
* Writing Custom Models::
* Writing Custom Cell Renderers::
@end menu

@c -----------------------------------------------------------------------------
@node Overview, GtkListStore and GtkTreeStore, Top, Top
@section Overview

@findex GtkTreeModel
@findex gtk-tree-model
@findex tree-model, gtk-tree-model

@findex gtkTreeView
@findex gtk-tree-view
@findex tree-view, gtk-tree-view

@findex GtkTreeViewColumn
@findex gtk-tree-view-column
@findex tree-view-column, gtk-tree-view-column

@findex GtkCellRenderer
@findex gtk-cell-renderer
@findex cell-renderer, gtk-cell-renderer

To create a tree or list in GTK+, use the @xurl{gtk-tree-model} interface in
conjunction with the @xurl{gtk-tree-view} widget.  This widget is designed
around a Model/View/Controller design and consists of four major parts:

@itemize
@item The tree view widget @xurl{gtk-tree-view}.
@item The view column @xurl{gtk-tree-view-column}.
@item The cell renderers @xurl{gtk-cell-renderer} etc.
@item The model interface @xurl{gtk-tree-model}.
@end itemize

The View is composed of the first three objects, while the last is the Model.
One of the prime benefits of the MVC design is that multiple views can be
created of a single model.  For example, a model mapping the file system could
be created for a file manager.  Many views could be created to display various
parts of the file system, but only one copy need be kept in memory.

The purpose of the cell renderers is to provide extensibility to the widget and
to allow multiple ways of rendering the same type of data.  For example,
consider how to render a boolean variable.  Should it render as a string of
"True" or "False", "On" or "Off", or should it be rendered as a checkbox?

@menu
* Creating a model::
* Creating the view component::
* Simple example::
@end menu

@c -----------------------------------------------------------------------------
@node Creating a model, Creating the view component, Overview
@subsection Creating a model

@findex GtkTreeStore
@findex gtk-tree-store
@findex tree-store, gtk-tree-store

@findex GtkListStore
@findex gtk-list-store
@findex list-store, gtk-list-store

GTK+ provides two simple models that can be used: the @xurl{gtk-list-store} and
the @xurl{gtk-tree-store}.  @xurl{gtk-list-store} is used to model list widgets,
while the @xurl{gtk-tree-store} models trees.  It is possible to develop a new
type of model, but the existing models should be satisfactory for all but the
most specialized of situations.  Creating the model is quite simple:

@verbatim
 (let ((model (make-instance 'gtk-list-store
                             :column-types '("gchararray" "guint"))))
   ... )
@end verbatim

@findex GtkTreeIter
@findex gtk-tree-iter
@findex tree-iter, gtk-tree-iter

@findex gtk-list-store-set
@findex list-store-set, gtk-list-store-set

@findex gtk-tree-store-set
@findex tree-store-set, gtk-tree-store-set

This creates a list store with two columns: a string column and a boolean
column.  Adding data to the model is done using @xurl{gtk-tree-store-set} or
@xurl{gtk-list-store-set}, depending upon which sort of model was created.  To
do this, a @xurl{gtk-tree-iter} must be acquired.  The iterator points to the
location where data will be added.

Once an iterator has been acquired, @xurl{gtk-tree-store-set} is used to apply
data to the part of the model that the iterator points to.  Consider the
following example:

@verbatim
 (let ((model (make-instance 'gtk-list-store
                             :column-types '("gchararray" "guint"))))
   (let ((iter (gtk-list-store-append model)))
     (gtk-list-store-set model iter "Klaus-Dieter Mustermann" 51))
   ... )
@end verbatim

This can be written more compact as:

@verbatim
 (let ((model (make-instance 'gtk-list-store
                             :column-types '("gchararray" "guint"))))
   (gtk-list-store-set model (gtk-list-store-append model)
                             "Klaus-Dieter Mustermann" 51)
   ... )
@end verbatim

It can be used to set the data in any or all columns in a given row.

@c -----------------------------------------------------------------------------
@node Creating the view component, Simple example, Creating a model
@subsection Creating the view component

While there are several different models to choose from, there is only one view
widget to deal with.  It works with either the list or the tree store.  Setting
up a @xurl{gtk-tree-view} is not a difficult matter.  It needs a
@xurl{gtk-tree-model} to know where to retrieve its data from.

@verbatim
 (let ((model (create-and-fill-model))
       (view (make-instance 'gtk-tree-view
                            :model model)))
   ... )
@end verbatim

@subheading Columns and cell renderers

Once the @xurl{gtk-tree-view} widget has a model, it will need to know how to
display the model.  It does this with columns and cell renderers.

@findex GtkCellRendererText
@findex gtk-cell-renderer-text
@findex cell-renderer-text, gtk-cell-renderer-text

@findex GtkCellRendererPixbuf
@findex gtk-cell-renderer-pixbuf
@findex cell-renderer-pixbuf, gtk-cell-renderer-pixbuf

@findex GtkCellRendererToggle
@findex gtk-cell-renderer-toggle
@findex cell-renderer-toggle, gtk-cell-renderer-toggle

Cell renderers are used to draw the data in the tree model in a way.  There are
a number of cell renderers that come with GTK+, including the
@xurl{gtk-cell-renderer-text}, @xurl{gtk-cell-renderer-pixbuf} and the
@xurl{gtk-cell-renderer-toggle}.  It is relatively easy to write a custom
renderer.

@findex GtkTreeViewColumn
@findex gtk-tree-view-column
@findex tree-view-column, gtk-tree-view-column

A @xurl{gtk-tree-view-column} is the object that @xurl{gtk-tree-view} uses to
organize the vertical columns in the tree view.  It needs to know the name of
the column to label for the user, what type of cell renderer to use, and which
piece of data to retrieve from the model for a given row.

@verbatim
 ;; Create renderers for the cells
 (let* ((renderer (gtk-cell-renderer-text-new))
        (column (gtk-tree-view-column-new-with-attributes "Name"
                                                          renderer
                                                          "text" 0)))
   (gtk-tree-view-append-column view column)
   ... )
@end verbatim

At this point, all the steps in creating a displayable tree have been covered.
The model is created, data is stored in it, a tree view is created and columns
are added to it.

@subheading Selection handling

Most applications will need to not only deal with displaying data, but also
receiving input events from users.  To do this, simply get a reference to a
selection object, connect to the "changed" signal and then to retrieve data
for the row selected:

@verbatim
 (let ((view (create-view-and-model))
       ;; Get the selection of the view
       (select (gtk-tree-view-get-selection view)))
   ;; Setup the selection handler
   (gtk-tree-selection-set-mode select :single)
   (g-signal-connect select "changed"
      (lambda (selection)
        (let* ((model (gtk-tree-view-get-model view))
               (iter (gtk-tree-selection-get-selected selection))
               (name (gtk-tree-model-get-value model iter 0)))
          (format t "You selected the name ~A.~%" name))))
   ... )
@end verbatim

@c -----------------------------------------------------------------------------
@node Simple example, , Creating the view component
@subsection Simple example

@ifnotinfo
@float Figure, figure-simple-tree-view
@caption{Simple Tree View}
@center @image{figures/simple-tree-view, 201pt}
@end float
@end ifnotinfo

Here is a simple example of using a @xurl{gtk-tree-view} widget in context of
the other widgets.  It simply creates a simple model and view, and puts them
together.

@float Example, example-simple-tree-view
@caption{A simple Tree View}
@end float
@verbatim
(defun create-and-fill-model ()
  (let ((model (make-instance 'gtk-list-store
                              :column-types '("gchararray" "guint"))))
    (gtk-list-store-set model (gtk-list-store-append model)
                              "Klaus-Dieter Mustermann" 51)
    (gtk-list-store-set model (gtk-list-store-append model)
                              "Ulrike Langhals" 23)
    (gtk-list-store-set model (gtk-list-store-append model)
                              "Marius Kalinowski" 91)
    model))

(defun create-view-and-model ()
  (let* ((model (create-and-fill-model))
         (view (make-instance 'gtk-tree-view
                              :model model)))
    ;; Create renderers for the cells
    (let* ((renderer (gtk-cell-renderer-text-new))
           (column (gtk-tree-view-column-new-with-attributes "Name"
                                                             renderer
                                                             "text" 0)))
      (gtk-tree-view-append-column view column))
    (let* ((renderer (gtk-cell-renderer-text-new))
           (column (gtk-tree-view-column-new-with-attributes "Age"
                                                             renderer
                                                             "text" 1)))
      (gtk-tree-view-append-column view column))
    view))

(defun example-simple-tree-view ()
  (within-main-loop
    (let ((window (make-instance 'gtk-window
                                 :title "Example Simple Tree View"
                                 :type :toplevel
                                 :border-width 12
                                 :default-width 300
                                 :default-height 200))
          (view (create-view-and-model)))
      (g-signal-connect window "destroy"
                        (lambda (widget)
                          (declare (ignore widget))
                          (leave-gtk-main)))
      (gtk-container-add window view)
      (gtk-widget-show-all window))))
@end verbatim

@c -----------------------------------------------------------------------------
@node GtkListStore and GtkTreeStore, Creating a Tree View, Overview, Top
@section GtkListStore and GtkTreeStore

Gtk+ comes with two built-in data stores (models): @xurl{gtk-list-store} and
@xurl{gtk-tree-store}.  As the names imply, @xurl{gtk-list-store} is used for
simple lists of data items where items have no hierarchical parent-child
relationships, and @xurl{gtk-tree-store} is used for tree-like data structures,
where items can have parent-child relationships.  A list of files in a directory
would be an example of a simple list structure, whereas a directory tree is an
example for a tree structure.  A list is basically just a special case of a tree
with none of the items having any children, so one could use a tree store to
maintain a simple list of items as well. The only reason @xurl{gtk-list-store}
exists is in order to provide an easier interface that does not need to cater
for child-parent relationships, and because a simple list model can be optimised
for the special case where no children exist, which makes it faster and more
efficient.  @xurl{gtk-list-store} and @xurl{gtk-tree-store} should cater for
most types of data an application developer might want to display in a
@xurl{gtk-tree-view}.

Tree model implementations like @xurl{gtk-list-store} and @xurl{gtk-tree-store}
will take care of the view side for you once you have configured the
@xurl{gtk-tree-view} to display what you want. If you change data in the store,
the model will notify the tree view and your data display will be updated.  If
you add or remove rows, the model will also notify the store, and your row will
appear in or disappear from the view as well.

@subsection How Data is Organised in a Store

A model (data store) has model columns and rows.  While a tree view will display
each row in the model as a row in the view, the model's columns are not to be
confused with a view's columns.  A model column represents a certain data field
of an item that has a fixed data type.  You need to know what kind of data you
want to store when you create a list store or a tree store, as you can not add
new fields later on.

For example, we might want to display a list of files. We would create a list
store with two fields: a field that stores the filename (i. e. a string) and a
field that stores the file size (i. e. an unsigned integer).  The filename would
be stored in column 0 of the model, and the file size would be stored in column
1 of the model.  For each file we would add a row to the list store, and set the
row's fields to the filename and the file size.

The GLib type system (GType) is used to indicate what type of data is stored in
a model column.  These are the most commonly used types:
@itemize
  @item @code{"gboolean"}
  @item @code{"gint"}, @code{"guint"}
  @item @code{"glong"}, @code{"gulong"}, @code{"gint64"}, @code{"guint64"}
  @item @code{"gfloat"}, @code{"gdouble"}
  @item @code{"gchararray"}
  @item @code{"gpointer"}
  @item @code{"GdkPixbuf"}
@end itemize

You do not need to understand the type system, it will usually suffice to know
the above types, so you can tell a list store or tree store what kind of data
you want to store.  Storing GObject-derived types is a special case that is
dealt with further below.

Here is an example of how to create a list store:
@verbatim
 (let ((store (make-instance 'gtk-list-store
                             :column-types '("gchararray" "guint"))))
   ... )
@end verbatim
This creates a new list store with two columns.  Column 0 stores a string and
column 1 stores an unsigned integer for each row.  At this point the model has
no rows yet of course.  Before we start to add rows, let's have a look at the
different ways used to refer to a particular row.

@subsection Refering to Rows

@subsubsection GtkTreePath

There are different ways to refer to a specific row.  The two you will have to
deal with are @xurl{gtk-tree-iter} and @xurl{gtk-tree-path}.

A @xurl{gtk-tree-path} is a comparatively straight-forward way to describe the
logical position of a row in the model.  As a @xurl{gtk-tree-view} always
displays all rows in a model, a tree path always describes the same row in both
model and view.

@ifnotinfo
@float Figure, tree-path
@caption{Tree Paths}
@center @image{figures/tree-path, 201pt}
@end float
@end ifnotinfo

The picture shows the tree path in string form next to the label.  Basically, it
just counts the children from the imaginary root of the tree view.  An empty
tree path string would specify that imaginary invisible root.  Now 'Songs' is
the first child (from the root) and thus its tree path is just "0". 'Videos' is
the second child from the root, and its tree path is "1".  'oggs' is the second
child of the first item from the root, so its tree path is "0:1".  So you just
count your way down from the root to the row in question, and you get your tree
path.

The implication of this way of refering to rows is as follows: if you insert or
delete rows in the middle or if the rows are resorted, a tree path might
suddenly refer to a completely different row than it refered to before the
insertion/deletion/resorting.  This is important to keep in mind.  See the
section on @code{GtkTreeRowReferences} below for a tree path that keeps updating
itself to make sure it always refers to the same row when the model changes.

You can get a new @xurl{gtk-tree-path} from a path in string form using the
function @xurl{gtk-tree-path-new-from-string}, and you can convert a given
@xurl{gtk-tree-path} into its string notation with the function
@xurl{gtk-tree-path-to-string}.  Usually you will rarely have to handle the
string notation, it is described here merely to demonstrate the concept of tree
paths.

Instead of the string notation, @xurl{gtk-tree-path} uses an integer array
internally.  You can get the depth, i. e. the nesting level, of a tree path with
the function @xurl{gtk-tree-path-get-depth}.  A depth of 0 is the imaginary
invisible root node of the tree view and model.  A depth of 1 means that the
tree path describes a top-level row.  As lists are just trees without child
nodes, all rows in a list always have tree paths of depth 1.  The function
@xurl{gtk-tree-path-get-indices} returns the internal integer array of a tree
path.  You will rarely need to operate with those either.

If you operate with tree paths, you are most likely to use a given tree path,
and use functions like @xurl{gtk-tree-path-up}, @xurl{gtk-tree-path-down},
@xurl{gtk-tree-path-next}, @xurl{gtk-tree-path-prev},
@xurl{gtk-tree-path-is-ancestor}, or @xurl{gtk-tree-path-is-descendant}.  Note
that this way you can construct and operate on tree paths that refer to rows
that do not exist in model or view.  The only way to check whether a path
is valid for a specific model, i. e. the row described by the path exists, is
to convert the path into an iter using the function
@xurl{gtk-tree-model-get-iter}.

@xurl{gtk-tree-path} is an opaque structure, with its details hidden from the
compiler.  If you need to make a copy of a tree path, use the function
@xurl{gtk-tree-path-copy}.

@subsubsection GtkTreeIter

Another way to refer to a row in a list or tree is @xurl{gtk-tree-iter}.  A tree
iter is just a structure that contains a couple of pointers that mean something
to the model you are using.  Tree iters are used internally by models, and they
often contain a direct pointer to the internal data of the row in question.  You
should never look at the content of a tree iter and you must not modify it
directly either.  All tree models, and therefore also @xurl{gtk-list-store} and
@xurl{gtk-tree-store}, must support the @xurl{gtk-tree-model} functions that
operate on tree iters.  Some of these functions are:

@table @code
  @item @xurl{gtk-tree-model-get-iter-first}
  Sets the given iter to the first top-level item in the list or tree.

  @item @xurl{gtk-tree-model-iter-next}
  Sets the given iter to the next item at the current level in a list or tree.

  @item @xurl{gtk-tree-model-iter-children}
  Sets the first given iter to the first child of the row referenced by the
  second iter; not very useful for lists, mostly useful for trees.

  @item @xurl{gtk-tree-model-iter-n-children}
  Returns the number of children the row referenced by the provided iter
  has.  If you pass @code{nil} instead of iter structure, this function will
  return the number of top-level rows.  You can also use this
  function to count the number of items in a list store.

  @item @xurl{gtk-tree-model-iter-nth-child}
  Sets the first iter to the n-th child of the row referenced by the second
  iter.  If you pass @code{nil} instead of an iter structure as the second iter,
  you can get the first iter set to the n-th row of a list.

  @item @xurl{gtk-tree-model-iter-parent}
  Sets the first iter to the parent of the row referenced by the second iter;
  does nothing for lists, only useful for trees.
@end table

Almost all of those functions return @emph{true} if the requested operation
succeeded, and return @code{nil} otherwise.  There are more functions that
operate on iters.  Check out the @xurl{gtk-tree-model} API reference for
details.

You might notice that there is no @code{gtk-tree-model-iter-prev}.  This is
unlikely to be implemented for a variety of reasons.  It should be fairly simple
to write a helper function that provides this functionality though once you have
read this section.

Tree iters are used to retrieve data from the store, and to put data into the
store.  You also get a tree iter as result if you add a new row to the store
using the functions @xurl{gtk-list-store-append} or
@xurl{gtk-tree-store-append}.

Tree iters are often only valid for a short time, and might become invalid if
the store changes with some models.  It is therefore usually a bad idea to store
tree iters, unless you really know what you are doing.  You can use the function
@xurl{gtk-tree-model-get-flags} to get a model's flags, and check whether the
@code{:iters-persist} flag is set, in which case a tree iter will be valid as
long as a row exists, yet still it is not advisable to store iter structures
unless you really mean to do that.  There is a better way to keep track of a row
over time: @code{GtkTreeRowReference}.

@subsubsection GtkTreeRowReference

A @xurl{gtk-tree-row-reference} is basically an object that takes a tree path,
and watches a model for changes.  If anything changes, like rows getting
inserted or removed, or rows getting re-ordered, the tree row reference object
will keep the given tree path up to date, so that it always points to the same
row as before.  In case the given row is removed, the tree row reference will
become invalid.

A new tree row reference can be created with the function
@xurl{gtk-tree-row-reference-new}, given a model and a tree path.  After that,
the tree row reference will keep updating the path whenever the model changes.
The current tree path of the row originally refered to when the tree row
reference was created can be retrieved with the function
@xurl{gtk-tree-row-reference-get-path}.  If the row has been deleted,
@code{nil} will be returned instead of of a tree path.

You can check whether the row referenced still exists with the function
@xurl{gtk-tree-row-reference-valid}.

For the curious: internally, the tree row reference connects to the tree model's
"row-inserted", "row-deleted", and "rows-reordered" signals and updates its
internal tree path whenever something happened to the model that affects the
position of the referenced row.

Note that using tree row references entails a small overhead.  This is hardly
significant for 99.9 % of all applications out there, but when you have multiple
thousands of rows and/or row references, this might be something to keep in
mind, because whenever rows are inserted, removed, or reordered, a signal will
be sent out and processed for each row reference.

If you have read the tutorial only up to here so far, it is hard to explain
really what tree row references are good for.  An example where tree row
references come in handy can be found further below in the section on removing
multiple rows in one go.

In practice, a programmer can either use tree row references to keep track of
rows over time, or store tree iters directly, if, and only if, the model has
persistent iters.  Both @xurl{gtk-list-store} and @xurl{gtk-tree-store} have
persistent iters, so storing iters is possible.  However, using tree row
references is definitively the right way to do things, even though it comes with
some overhead that might impact performance in case of trees that have a very
large number of rows, in that case it might be preferable to write a custom
model anyway though.  Especially beginners might find it easier to handle and
store tree row references than iters, because tree row references are handled by
pointer value, which you can easily add to a list or pointer array, while it is
easy to store tree iters in a wrong way.

@subsubsection Usage

Tree iters can easily be converted into tree paths using the function
@xurl{gtk-tree-model-get-path}, and tree paths can easily be converted into tree
iters using the function @xurl{gtk-tree-model-get-iter}.  Here is an example
that shows how to get the iter from the tree path that is passed to us from the
tree view in the "row-activated" signal callback.  We need the iter here to
retrieve data from the store.

@float Example, example-row-activated
@caption{Converting a @xurl{gtk-tree-path} into a @xurl{gtk-tree-iter}}
@end float
@verbatim
;; Signal handler for the signal "row-activated"
(g-signal-connect view "row-activated"
   (lambda (view path col)
     (declare (ignore col))
     (let* ((model (gtk-tree-view-get-model view))
            ;; Get the iter from the path
            (iter (gtk-tree-model-get-iter model path)))
       (when iter
         (format t
                 "The row containing the name ~A has been double-clicked.~%"
                 (gtk-tree-model-get-value model iter 0))))))
@end verbatim

Tree row references reveal the current path of a row with the function
@xurl{gtk-tree-row-reference-get-path}.  There is no direct way to get a tree
iter from a tree row reference, you have to retrieve the tree row reference's
path first and then convert that into a tree iter.  As tree iters are only valid
for a short time, they are usually allocated on the stack, as in the following
example (keep in mind that @xurl{gtk-tree-iter} is just a structure that
contains data fields you do not need to know anything about).

@float Example, example-traverse-list
@caption{Going through every row in a list store.}
@end float
@verbatim
;; A signal handler which goes through every row in a list store
(g-signal-connect button "clicked"
   (lambda (button)
     (declare (ignore button))
     (let ((model (gtk-tree-view-get-model view)))
       (do ((iter (gtk-tree-model-get-iter-first model)
                  (gtk-tree-model-iter-next model iter)))
           ((not iter))
           (gtk-list-store-set-value model iter 1 0)))))
@end verbatim

The code above asks the model to fill the iter structure to make it point to the
first row in the list store.  If there is a first row and the list store is not
empty, the iter will be set, and the function
@xurl{gtk-tree-model-get-iter-first} will return @emph{true}.  If there is no
first row, it will just return @code{nil}.  If a first row exists, the while
loop will be entered and we change some of the first row's data.  Then we ask
the model to make the given iter point to the next row, until there are no more
rows, which is when the function @xurl{gtk-tree-model-iter-next} returns
@code{nil}.  Instead of traversing the list store we could also have used
@xurl{gtk-tree-model-foreach}.

@subsection Adding Rows to a Store
@subsubsection Adding Rows to a List Store

Rows are added to a list store with the function @xurl{gtk-list-store-append}.
This will insert a new empty row at the end of the list.  There are other
functions, documented in the @xurl{gtk-list-store} API reference, that give you
more control about where exactly the new row is inserted, but as they work very
similar to the function @xurl{gtk-list-store-append} and are fairly
straight-forward to use, we will not deal with them here.  Here is a simple
example of how to create a list store and add an empty row to it.

@verbatim
 (let* ((model (make-instance 'gtk-tree-store
                              :column-types '("gchararray")))
        ;; Append an empty row to the list store
        (iter (gtk-list-store-append model nil)))
   ... )
@end verbatim

This in itself is not very useful yet of course.  We will add data to the rows
in the next section.

@subsubsection Adding Rows to a Tree Store

Adding rows to a tree store works similar to adding rows to a list store, only
that the function @xurl{gtk-tree-store-append} is the function to use and one
more argument is required, namely the tree iter to the parent of the row to
insert.  If you supply @code{nil} instead of providing the tree iter of another
row, a new top-level row will be inserted.  If you do provide a parent tree
iter, the new empty row will be inserted after any already existing children of
the parent.  Again, there are other ways to insert a row into the tree store and
they are documented in the @xurl{gtk-tree-store} API reference manual.  Another
short example

@verbatim
 (let* ((model (make-instance 'gtk-tree-store
                              :column-types '("gchararray")))
        ;; Append an empty top-level row to the tree store.
        ;; Iter will point to the new row.
        (iter (gtk-tree-store-append model nil))
        (child nil))
   ;; Append another empty top-level row to the tree store.
   (setf iter (gtk-tree-store-append model nil))
   ;; Append a child to the row we just added.
   (setf child (gtk-tree-store-append model iter))
   ;; Get the first row, and add a child to it as well (could have been done
   ;; right away earlier of course, this is just for demonstration purposes)
   (setf iter (gtk-tree-model-get-iter-first model))
   (setf child (gtk-tree-store-append model iter))
   ... )
@end verbatim

@subsubsection Speed Issues when Adding a Lot of Rows

A common scenario is that a model needs to be filled with a lot of rows at some
point, either at start-up, or when some file is opened.  An equally common
scenario is that this takes an awfully long time even on powerful machines once
the model contains more than a couple of thousand rows, with an exponentially
decreasing rate of insertion.  As already pointed out above, writing a custom
model might be the best thing to do in this case.  Nevertheless, there are some
things you can do to work around this problem and speed things up a bit even
with the stock Gtk+ models:

Firstly, you should detach your list store or tree store from the tree view
before doing your mass insertions, then do your insertions, and only connect
your store to the tree view again when you are done with your insertions.
Like this:

@verbatim
(let ((model (gtk-tree-view-get-model view)))
  ;; Detach model from view
  (gtk-tree-view-set-model view nil)

  ... insert a couple of thousand rows ...

  ;; Re-attach model to view
  (gtk-tree-view-set-model view model)

  ...)
@end verbatim

Secondly, you should make sure that sorting is disabled while you are doing your
mass insertions, otherwise your store might be resorted after each and every
single row insertion, which is going to be everything but fast.  Thirdly, you
should not keep around a lot of tree row references if you have so many rows,
because with each insertion (or removal) every single tree row reference will
check whether its path needs to be updated or not.

@subsection Manipulating Row Data

Adding empty rows to a data store is not terribly exciting, so let's see how we
can add or change data in the store.  The functions @xurl{gtk-list-store-set}
and @xurl{gtk-tree-store-set} are used to manipulate a given row's data. There
is also @xurl{gtk-list-store-set-value} and @xurl{gtk-tree-store-set-value}, but
those should only be used by people familiar with GLib's GValue system.

Both functions @xurl{gtk-list-store-set} and @xurl{gtk-tree-store-set} take a
variable number of arguments.  The first two arguments are a pointer to the
model, and the iter pointing to the row whose data we want to change.  They are
followed by a variable number of (column, data) argument pairs.  The column
refers to the model column number and is usually an enum value (to make the code
more readable and to make changes easier).  The data should be of the same data
type as the model column.  Here is an example where we create a store that
stores two strings and one integer for each row:

@verbatim
 (let ((model (make-instance 'gtk-list-store
                             :column-types '("gchararray" "guint"))))
   (gtk-list-store-set model (gtk-list-store-append model)
                             "Klaus-Dieter Mustermann" 51)
   ... )
@end verbatim

You do not need to worry about allocating and freeing memory for the data to
store.  The model (or more precisely: the GLib/GObject GType and GValue system)
will take care of that for you.  If you store a string, for example, the model
will make a copy of the string and store that.  If you then set the field to a
new string later on, the model will automatically free the old string and again
make a copy of the new string and store the copy.  This applies to almost all
types, be it @code{G_TYPE_STRING} or @code{GDK_TYPE_PIXBUF}.

The exception to note is @code{G_TYPE_POINTER}.  If you allocate a chunk of
data or a complex structure and store it in a @code{G_TYPE_POINTER} field, only
the pointer value is stored.  The model does not know anything about the size or
content of the data your pointer refers to, so it could not even make a copy if
it wanted to, so you need to allocate and free the memory yourself in this case.
However, if you do not want to do that yourself and want the model to take care
of your custom data for you, then you need to register your own type and derive
it from one of the GLib fundamental types (usually @code{G_TYPE_BOXED}).  See
the GObject GType reference manual for details.  Making a copy of data involves
memory allocation and other overhead of course, so one should consider the
performance implications of using a custom GLib type over a
@code{G_TYPE_POINTER} carefully before taking that approach.  Again, a custom
model might be the better alternative, depending on the overall amount of data
to be stored (and retrieved).

@subsection Retrieving Row Data

Storing data is not very useful if it cannot be retrieved again.  This is done
using the function @xurl{gtk-tree-model-get}, which takes similar arguments as
the functions @xurl{gtk-list-store-set} or @xurl{gtk-tree-store-set} do, only
that it takes (column, pointer) arguments.  The pointer must point to a variable
that is of the same type as the data stored in that particular model column.

Here is the previous example extended to traverse the list store and print out
the data stored.  As an extra, we use the function @xurl{gtk-tree-model-foreach}
to traverse the store and retrieve the row number from the GtkTreePath passed to
us in the foreach callback function:

@verbatim
(defun foreach-func (model path iter)
  (let ((first-name (gtk-tree-model-get-value model iter 0))
        (last-name (gtk-tree-model-get-value model iter 1))
        (age (gtk-tree-model-get-value model iter 2))
        (tree-path (gtk-tree-path-to-string path)))
    (format t "Row ~A: ~A ~A, age ~A~%" tree-path first-name last-name age)))

(defun create-and-fill-and-dump-model ()
  (let ((model (make-instance 'gtk-list-store
                              :column-types
                              '("gchararray" "gchararray" "guint"))))
    ;; Fill the model with data
    (gtk-list-store-set model (gtk-list-store-append model)
                              "Klaus-Dieter" "Mustermann" 51)
    (gtk-list-store-set model (gtk-list-store-append model)
                              "Ulrike" "Langhals" 23)
    (gtk-list-store-set model (gtk-list-store-append model)
                              "Marius" "Kalinowski" 91)
    ;; Now traverse the list
    (gtk-tree-model-foreach model #'foreach-func)))
@end verbatim

Note that when a new row is created, all fields of a row are set to a default
@code{nil} value appropriate for the data type in question.  A field of type
@code{G_TYPE_INT} will automatically contain the value 0 until it is set to a
different value, and strings and all kind of pointer types will be @code{nil}
until set to something else.  Those are valid contents for the model, and if you
are not sure that row contents have been set to something, you need to be
prepared to handle @code{NULL} pointers and the like in your code.  Run the
above program with an additional empty row and look at the output to see this in
effect.

@subsection Removing Rows

Rows can easily be removed with the functions @xurl{gtk-list-store-remove} and
@xurl{gtk-tree-store-remove}.  The removed row will automatically be removed
from the tree view as well, and all data stored will automatically be freed,
with the exception of G_TYPE_POINTER columns (see above).

Removing a single row is fairly straight forward: you need to get the iter that
identifies the row you want to remove, and then use one of the above functions.
Here is a simple example that removes a row when you double-click on it (bad
from a user interface point of view, but then it is just an example):

@verbatim
 ;; Signal handler for the signal "row-activated"
 (g-signal-connect view "row-activated"
   (lambda (view path col)
     (declare (ignore col))
     (let* ((model (gtk-tree-view-get-model view))
            (iter (gtk-tree-model-get-iter model path)))
       (when iter
         (gtk-list-store-remove model iter)))))
@end verbatim

If you want to remove the n-th row from a list (or the n-th child of a tree
node), you have two approaches: either you first create a @xurl{gtk-tree-path}
that describes that row and then turn it into an iter and remove it; or you take
the iter of the parent node and use the function
@xurl{gtk-tree-model-iter-nth-child} (which will also work for list stores if
you use @code{nil} as the parent iter. Of course you could also start with the
iter of the first top-level row, and then step-by-step move it to the row you
want, although that seems a rather awkward way of doing it.  The following code
snippet will remove the n-th row of a list if it exists:

@verbatim
;; Removes the nth row of a list store if it exists.
(defun list-store-remove-nth-row (store n)
  (let (;; nil means the parent is the virtual root node, so the
        ;; n-th top-level element is returned in iter, which is
        ;; the n-th row in a list store as a list store only has
        ;; top-level elements, and no children
        (iter (gtk-tree-model-nth-child store nil n)))
    (when iter
      (gtk-list-store-remove store iter))))
@end verbatim

Removing multiple rows at once can be a bit tricky at times, and requires some
thought on how to do this best.  For example, it is not possible to traverse a
store with the function @xurl{gtk-tree-model-foreach}, check in the callback
function whether the given row should be removed and then just remove it by
calling one of the stores' remove functions.  This will not work, because the
model is changed from within the foreach loop, which might suddenly invalidate
formerly valid tree iters in the foreach function, and thus lead to
unpredictable results.

Here is an example for an alternative approach to removing multiple rows in one
go. Here we want to remove all rows from the store that contain persons that
are older than 30, but it could just as well be all selected rows or
some other criterion:

@verbatim
...

(let ((rowref-list nil))
  (defun foreach-func (model path iter)
    (let ((age (gtk-tree-model-get-value model iter 2)))
      (when (> age 30)
        (let ((rowref (gtk-tree-row-reference-new model path)))
          (setf rowref-list (cons rowref rowref-list))))
      nil))

  (defun remove-people-older-than (model)
    (setf rowref-list nil)
    (gtk-tree-model-foreach model #'foreach-func)
    (dolist (rowref rowref-list)
      (let ((path (gtk-tree-row-reference-get-path rowref)))
      (when path
        (let ((iter (gtk-tree-model-get-iter model path)))
          (when iter
            (gtk-list-store-remove model iter))))))))

...
@end verbatim

The functions @xurl{gtk-list-store-clear} and @xurl{gtk-tree-store-clear} come
in handy if you want to remove all rows.

@c @subsection Storing GObjects (Pixbufs etc.)

@c -----------------------------------------------------------------------------
@node Creating a Tree View, Mapping Data to the Screen, GtkListStore and GtkTreeStore
@section Creating a Tree View

In order to display data in a tree view widget, we need to create one first, and
we need to instruct it where to get the data to display from.  A new tree view
is created with:

@verbatim
(let ((view (make-instance 'gtk-tree-view)))
  ... )
@end verbatim

@subsection Connecting Tree View and Model

Before we proceed to the next section where we display data on the screen, we
need connect our data store to the tree view, so it knows where to get the data
to display from.  This is achieved with the function
@xurl{gtk-tree-view-set-model}, which will by itself do very little.  However,
it is a prerequisite for what we do in the following sections.

The function @xurl{gtk-tree-view-new-with-model} is a convenience function for
the previous two.  The function @xurl{gtk-tree-view-get-model} will return the
model that is currently attached to a given tree view, which is particularly
useful in callbacks where you only get passed the tree view widget (after all,
we do not want to go down the road of global variables, which will inevitably
lead to the Dark Side, do we?).

@subsubsection Reference counting

Tree models like @xurl{gtk-list-store} and @xurl{gtk-tree-store} are GObjects
and have a reference count of 1 after creation.  The tree view will add its own
reference to the model when you add the model with the function
@xurl{gtk-tree-view-set-model}, and will unref it again when you replace the
model with another model, unset the model by passing @code{nil} as a model, or
when the tree view is destroyed.

This means that you need to take care of "your" reference yourself, otherwise
the model will not be destroyed properly when you disconnect it from the tree
view, and its memory will not be freed (which does not matter much if the same
model is connected to the tree view from application start to end).  If you plan
to use the same model for a tree view for the whole duration of the application,
you can get rid of "your" reference right after you have connected the model to
the view - then the model will be destroyed automatically when the tree view is
destroyed (which will be automatically destroyed when the window it is in is
destroyed):

@verbatim
(let* ((model (make-instance 'gtk-list-store
                             :column-types '("gchararray")))
       (view (make-instance 'gtk-tree-view
                            :model model)))
  ... )
@end verbatim

@subsection Tree View Look and Feel

There are a couple of ways to influence the look and feel of the tree view.  You
can hide or show column headers with the function
@xurl{gtk-tree-view-set-headers-visible}, and set them clickable or not with
the function @xurl{gtk-tree-view-set-headers-clickable} (which will be done
automatically for you if you enable sorting).

The function @xurl{gtk-tree-view-set-rules-hint} will enable or disable rules in
the tree view.  'Rules' means that every second line of the tree view has a
shaded background, which makes it easier to see which cell belongs to which row
in tree views that have a lot of columns.  As the function name implies, this
setting is only a hint; in the end it depends on the active Gtk+ theme engine if
the tree view shows ruled lines or not.  Users seem to have strong feelings
about rules in tree views, so it is probably a good idea to provide an option
somewhere to disable rule hinting if you set it on tree views (but then, people
also seem to have strong feelings about options abundance and 'sensible' default
options, so whatever you do will probably upset someone at some point).

The expander column can be set with the function
@xurl{gtk-tree-view-set-expander-column}.  This is the column where child
elements are indented with respect to their parents, and where rows with
children have an 'expander' arrow with which a node's children can be collapsed
(hidden) or expanded (shown). By default, this is the first column.







@c -----------------------------------------------------------------------------
@node Mapping Data to the Screen, Selections Double-Clicks and Context Menus, Creating a Tree View
@section Mapping Data to the Screen

As outlined above, tree view columns represent the visible columns on the screen
that have a column header with a column name and can be resized or sorted.  A
tree view is made up of tree view columns, and you need at least one tree view
column in order to display something in the tree view.  Tree view columns,
however, do not display anything by themselves, this is done by specialised
@xurl{gtk-cell-renderer} objects.  Cell renderers are packed into tree view
columns much like widgets are packed into @xurl{gtk-box}es.

Here is a diagram (courtesy of Owen Taylor) that pictures the relationship
between tree view columns and cell renderers:

@ifnotinfo
@float Figure, figure-tree-view-column
@caption{GtkTreeViewColumn}
@center @image{figures/tree-view-column, 313pt}
@end float
@end ifnotinfo

In the above diagram, both 'Country' and 'Representative' are tree view columns,
where the 'Country' and 'Representative' labels are the column headers.  The
'Country' column contains two cell renderers, one to display the flag icons, and
one to display the country name.  The 'Representative' column only contains one
cell renderer to display the representative's name.

@c -----------------------------------------------------------------------------
@subsection Cell Renderers

Cell renderers are objects that are responsible for the actual rendering of data
within a @xurl{gtk-tree-view-column}.  They are basically just GObjects (i. e.
not widgets) that have certain properties, and those properties determine how a
single cell is drawn.

In order to draw cells in different rows with different content, a cell
renderer's properties need to be set accordingly for each single row/cell to
render.  This is done either via attributes or cell data functions (see below).
If you set up attributes, you tell Gtk which model column contains the data from
which a property should be set before rendering a certain row.  Then the
properties of a cell renderer are set automatically according to the data in the
model before each row is rendered.  Alternatively, you can set up cell data
functions, which are called for each row to be rendererd, so that you can
manually set the properties of the cell renderer before it is rendered.  Both
approaches can be used at the same time as well.  Lastly, you can set a cell
renderer property when you create the cell renderer.  That way it will be used
for all rows/cells to be rendered (unless it is changed later of course).

Different cell renderers exist for different purposes:
@table @code
  @item @xurl{gtk-cell-renderer-text}
  renders strings or numbers or boolean values as text ("Joe", "99.32", "true").

  @item @xurl{gtk-cell-renderer-pixbuf}
  is used to display images; either user-defined images, or one of the stock
  icons that come with Gtk+.

  @item @xurl{gtk-cell-renderer-toggle}
  displays a boolean value in form of a check box or as a radio button.

  @item @xurl{gtk-cell-editable}
  is a special cell that implements editable cells (i. e. @xurl{gtk-entry} or
  @xurl{gtk-spin-button} in a treeview).  This is not a cell renderer!  If you
  want to have editable text cells, use @xurl{gtk-cell-renderer-text} and make
  sure the "editable" property is set.  @xurl{gtk-cell-editable} is only used by
  implementations of editable cells and widgets that can be inside of editable
  cells.  You are unlikely to ever need it.
@end table

Contrary to what one may think, a cell renderer does not render just one single
cell, but is responsible for rendering part or whole of a tree view column for
each single row.  It basically starts in the first row and renders its part of
the column there.  Then it proceeds to the next row and renders its part of the
column there again.  And so on.

How does a cell renderer know what to render? A cell renderer object has certain
'properties' that are documented in the API reference (just like most other
objects, and widgets).  These properties determine what the cell renderer is
going to render and how it is going to be rendered.  Whenever the cell renderer
is called upon to render a certain cell, it looks at its properties and renders
the cell accordingly.  This means that whenever you set a property or change a
property of the cell renderer, this will affect all rows that are rendered after
the change, until you change the property again.

Here is a diagram (courtesy of Owen Taylor) that tries to show what is going on
when rows are rendered:

@ifnotinfo
@float Figure, figure-cell-renderer-properties
@caption{Cell Renderer Properties}
@center @image{figures/cell-renderer-properties, 314pt}
@end float
@end ifnotinfo

The above diagram shows the process when attributes are used. In the example, a
text cell renderer's "text" property has been linked to the first model column.
The "text" property contains the string to be rendered.  The "foreground"
property, which contains the colour of the text to be shown, has been linked to
the second model column.  Finally, the "strikethrough" property, which
determines whether the text should be with a horizontal line that strikes
through the text, has been connected to the third model column (of type
@code{G_TYPE_BOOLEAN}).

With this setup, the cell renderer's properties are 'loaded' from the model
before each cell is rendered.

Here is a silly and utterly useless little example that demonstrates this
behaviour, and introduces some of the most commonly used properties of
@xurl{gtk-cell-renderer-text}:

@verbatim
(defun create-and-fill-model ()
  (let ((model (make-instance 'gtk-tree-store
                              :column-types '("gchararray" "gchararray"))))
    ;; Append a top level row and leave it empty
    (gtk-tree-store-append model nil)
    ;; Append a second top level row, and fill it with some data
    (let ((parent (gtk-tree-store-set model (gtk-tree-store-append model nil)
                                            "Joe" "Average")))
      ;; Append a child to the second top level row, and fill in some data
      (gtk-tree-store-set model (gtk-tree-store-append model parent)
                                "Jane" "Average"))
    model))

(defun create-view-and-model ()
  (let* ((model (create-and-fill-model))
         (view (make-instance 'gtk-tree-view
                              :model model)))
  ;; Create the first column
  (let* ((column (make-instance 'gtk-tree-view-column
                                :title "First Name"))
         (renderer (make-instance 'gtk-cell-renderer-text
                                  :text "Booooo!")))
    ;; pack tree view column into tree view
    (gtk-tree-view-append-column view column)
    ;; pack cell renderer into tree view column
    (gtk-tree-view-column-pack-start column renderer))

  ;; Create the second column
  (let* ((column (make-instance 'gtk-tree-view-column
                                :title "Last Name"))
         (renderer (make-instance 'gtk-cell-renderer-text
                                  :cell-background "Orange"
                                  :cell-background-set t)))
    ;; pack tree view column into tree view
    (gtk-tree-view-append-column view column)
    ;; pack cell renderer into tree view column
    (gtk-tree-view-column-pack-start column renderer))
  ;; No selection possible
  (gtk-tree-selection-set-mode (gtk-tree-view-get-selection view) :none)
  view))

(defun example-cell-renderer-properties ()
  (within-main-loop
    (let ((window (make-instance 'gtk-window
                                 :title "Example Cell Renderer Properties"
                                 :type :toplevel
                                 :default-width 350
                                 :default-height 200))
          (view (create-view-and-model-3)))
      (g-signal-connect window "destroy"
                        (lambda (widget)
                          (declare (ignore widget))
                          (leave-gtk-main)))
      (gtk-container-add window view)
      (gtk-widget-show-all window))))
@end verbatim

The above code should produce something looking like this:

@ifnotinfo
@float Figure, figure-renderer-properties
@caption{Persistent Cell Renderer Properties}
@center @image{figures/renderer-properties, 235pt}
@end float
@end ifnotinfo

It looks like the tree view display is partly correct and partly incomplete.  On
the one hand the tree view renders the correct number of rows, and it displays
the hierarchy correctly (on the left), but it does not display any of the data
that we have stored in the model.  This is because we have made no connection
between what the cell renderers should render and the data in the model.  We
have simply set some cell renderer properties on start-up, and the cell
renderers adhere to those set properties meticulously.

There are two different ways to connect cell renderers to data in the model:
attributes and cell data functions.

@c -----------------------------------------------------------------------------
@subsection Attributes

An attribute is a connection between a cell renderer property and a field/column
in the model.  Whenever a cell is to be rendered, a cell renderer property will
be set to the values of the specified model column of the row that is to be
rendered.  It is very important that the column's data type is the same type
that a property takes according to the API reference manual. Here is some code
to look at:

@verbatim
 (let* ((renderer (gtk-cell-renderer-text-new))
        (column (gtk-tree-view-column-new-with-attributes "Example"
                                                          renderer
                                                          "text" 0)))
   (gtk-tree-view-append-column view column)
   ... )
@end verbatim

This means that the text cell renderer property "text" will be set to the string
in model column 0 of each row to be drawn.

Again, when setting attributes it is very important that the data type stored in
a model column is the same as the data type that a property requires as
argument.  Check the API reference manual to see the data type that is required
for each property.  When reading through the example a bit further above, you
might have noticed that we set the "cell-background" property of a
@xurl{gtk-cell-renderer-text}, even though the API documentation does not list
such a property.  We can do this, because @xurl{gtk-cell-renderer-text} is
derived from @xurl{gtk-cell-renderer}, which does in fact have such a property.
Derived classes inherit the properties of their parents.  This is the same as
with widgets that you can cast into one of their ancestor classes.  The API
reference has an object hierarchy that shows you which classes a widget or some
other object is derived from.

There are two more noteworthy things about @xurl{gtk-cell-renderer} properties:
one is that sometimes there are different properties which do the same, but take
different arguments, such as the @code{"foreground"} and
@code{"foreground-rgba"} properties of @xurl{gtk-cell-renderer-text} (which
specify the text colour).  The @code{"foreground"} property take a colour in
string form, such as "Orange" or "CornflowerBlue", whereas "foreground-rgba"
takes a @xurl{gdk-rgba} argument.  It is up to you to decide which one to use -
the effect will be the same.  The other thing worth mentioning is that most
properties have a @code{"foo-set"} property taking a boolean value as argument,
such as @code{"foreground-set"}.  This is useful when you want to have a certain
setting have an effect or not.  If you set the @code{"foreground"} property, but
set @code{"foreground-set"} to @code{nil}, then your foreground color setting
will be disregarded.  This is useful in cell data functions (see below), or, for
example, if you want set the foreground colour to a certain value at start-up,
but only want this to be in effect in some columns, but not in others (in which
case you could just connect the @code{"foreground-set"} property to a model
column of type @code{G_TYPE_BOOLEAN} with the function
@xurl{gtk-tree-view-column-add-attribute}.

Setting column attributes is the most straight-forward way to get your model
data to be displayed.  This is usually used whenever you want the data in the
model to be displayed exactly as it is in the model.

Another way to get your model data displayed on the screen is to set up cell
data functions.

@c -----------------------------------------------------------------------------
@subsection Cell Data Functions

A cell data function is a function that is called for a specific cell renderer
for each single row before that row is rendered.  It gives you maximum control
over what exactly is going to be rendered, as you can set the cell renderer's
properties just like you want to have them.  Remember not only to set a property
if you want it to be active, but also to unset a property if it should not be
active (and it might have been set in the previous row).

Cell data functions are often used if you want more fine-grained control over
what is to be displayed, or if the standard way to display something is not
quite like you want it to be.  A case in point are floating point numbers.  If
you want floating point numbers to be displayed in a certain way, say with only
one digit after the colon/comma, then you need to use a cell data function.  Use
@xurl{gtk-tree-view-column-set-cell-data-func} to set up a cell data function
for a particular cell renderer. Here is an example:

@verbatim
   enum
   {
     COLUMN_NAME = 0,
     COLUMN_AGE_FLOAT,
     NUM_COLS
   };

   ...

   void
   age_cell_data_function (GtkTreeViewColumn *col,
                           GtkCellRenderer   *renderer,
                           GtkTreeModel      *model,
                           GtkTreeIter       *iter,
                           gpointer           user_data)
   {
     gfloat  age;
     gchar   buf[20];

     gtk_tree_model_get(model, iter, COLUMN_AGE_FLOAT, &age, -1);

     g_snprintf(buf, sizeof(buf), "%.1f", age);

     g_object_set(renderer, "text", buf, NULL);
   }

   ...

   liststore = gtk_list_store_new(NUM_COLS, G_TYPE_STRING, G_TYPE_FLOAT);

   col = gtk_tree_view_column_new();

   cell = gtk_cell_renderer_text_new();

   gtk_tree_view_column_pack_start(col, cell, TRUE);

   gtk_tree_view_column_set_cell_data_func(col,
                                           cell,
                                           age_cell_data_func,
                                           NULL, NULL);

   ...
@end verbatim

For each row to be rendered by this particular cell renderer, the cell data
function is going to be called, which then retrieves the float from the model,
and turns it into a string where the float has only one digit after the
colon/comma, and renders that with the text cell renderer.

This is only a simple example, you can make cell data functions a lot more
complicated if you want to.  As always, there is a trade-off to keep in mind
though.  Your cell data function is going to be called every single time a cell
in that (renderer) column is going to be rendered.  Go and check how often this
function is called in your program if you ever use one.  If you do
time-consuming operations within a cell data function, things are not going to
be fast, especially if you have a lot of rows.  The alternative in this case
would have been to make an additional column @code{COLUMN_AGE_FLOAT_STRING} of
type @code{G_TYPE_STRING}, and to set the float in string form whenever you set
the float itself in a row, and then hook up the string column to a text cell
renderer using attributes.  This way the float to string conversion would only
need to be done once.  This is a cpu cycles / memory trade-off, and it depends
on your particular case which one is more suitable.  Things you should probably
not do is to convert long strings into UTF8 format in a cell data function, for
example.

You might notice that your cell data function is called at times even for rows
that are not visible at the moment.  This is because the tree view needs to know
its total height, and in order to calculate this it needs to know the height of
each and every single row, and it can only know that by having it measured,
which is going to be slow when you have a lot of rows with different heights
(if your rows all have the same height, there should not be any visible delay
though).

@subheading GtkCellRendererText and Integer, Boolean and Float Types

It has been said before that, when using attributes to connect data from the
model to a cell renderer property, the data in the model column specified in the
function @xurl{gtk-tree-view-column-add-attribute} must always be of the same
type as the data type that the property requires.

This is usually true, but there is an exception: if you use the function
@xurl{gtk-tree-view-column-add-attribute} to connect a text cell renderer's
"text" property to a model column, the model column does not need to be of
@code{G_TYPE_STRING}, it can also be one of most other fundamental GLib types,
e. g. @code{G_TYPE_BOOLEAN}, @code{G_TYPE_INT}, @code{G_TYPE_UINT},
@code{G_TYPE_LONG}, @code{G_TYPE_ULONG}, @code{G_TYPE_INT64},
@code{G_TYPE_UINT64}, @code{G_TYPE_FLOAT}, or @code{G_TYPE_DOUBLE}.  The text
cell renderer will automatically display the values of these types correctly in
the tree view. For example:

@verbatim
  enum
  {
    COL_NAME = 0,
    COL_YEAR_BORN,
    NUM_COLS
  };

  liststore = gtk_list_store_new(NUM_COLS, G_TYPE_STRING, G_TYPE_UINT);

  ...

  cell = gtk_cell_renderer_text_new();
  col = gtk_tree_view_column_new();
  gtk_tree_view_column_add_attribute(col, cell, "text", COL_YEAR_BORN);

  ...
@end verbatim

Even though the "text" property would require a string value, we use a model
column of an integer type when setting attributes.  The integer will then
automatically be converted into a string before the cell renderer property is
set.

If you are using a floating point type, i. e. @code{G_TYPE_FLOAT} or
@code{G_TYPE_DOUBLE}, there is no way to tell the text cell renderer how many
digits after the floating point (or comma) should be rendered.  If you only want
a certain amount of digits after the point/comma, you will need to use a cell
data function.

@c -----------------------------------------------------------------------------
@subsection GtkCellRendererText, UTF8, and pango markup

All text used in Gtk+-2.0 widgets needs to be in UTF8 encoding, and
@xurl{gtk-cell-renderer-text} is no exception.  Text in plain ASCII is
automatically valid UTF8, but as soon as you have special characters that do not
exist in plain ASCII (usually characters that are not used in the English
language alphabet), they need to be in UTF8 encoding.  There are many different
character encodings that all specify different ways to tell the computer which
character is meant.  Gtk+-2.0 uses UTF8, and whenever you have text that is in a
different encoding, you need to convert it to UTF8 encoding first, using one of
the GLib @code{g_convert} family of functions.  If you only use text input from
other Gtk+ widgets, you are on the safe side, as they will return all text in
UTF8 as well.

However, if you use 'external' sources of text input, then you must convert that
text from the text's encoding (or the user's locale) to UTF8, or it will not be
rendered correctly (either not at all, or it will be cut off after the first
invalid character).  Filenames are especially hard, because there is no
indication whatsoever what character encoding a filename is in (it might have
been created when the user was using a different locale, so filename encoding is
basically unreliable and broken).  You may want to convert to UTF8 with fallback
characters in that case.  You can check whether a string is valid UTF8 with
@code{g_utf8_validate}.  You should, in this author's opinion at least, put
these checks into your code at crucial places wherever it is not affecting
performance, especially if you are an English-speaking programmer that has
little experience with non-English locales.  It will make it easier for others
and yourself to spot problems with non-English locales later on.

In addition to the @code{"text"} property, @xurl{gtk-cell-renderer-text} also
has a @code{"markup"} property that takes text with pango markup as input.
Pango markup allows you to place special tags into a text string that affect the
style the text is rendered (see the pango documentation).  Basically you can
achieve everything you can achieve with the other properties also with pango
markup (only that using properties is more efficient and less messy).  Pango
markup has one distinct advantage though that you cannot achieve with text cell
renderer properties: with pango markup, you can change the text style in the
middle of the text, so you could, for example, render one part of a text string
in bold print, and the rest of the text in normal.  Here is an example of a
string with pango markup:

"You can have text in @code{<b>bold</b>} or in a
@code{<span color='Orange'>different color</span>}"

When using the @code{"markup"} property, you need to take into account that the
@code{"markup"} and @code{"text"} properties do not seem to be mutually
exclusive (I suppose this could be called a bug). In other words: whenever you
set @code{"markup"} (and have used the @code{"text"} property before), set the
@code{"text"} property to @code{nil}, and vice versa. Example:

@verbatim
  ...

  void
  foo_cell_data_function ( ... )
  {
    ...
    if (foo->is_important)
      g_object_set(renderer, "markup",
                             "<b>important</b>", "text", NULL, NULL);
    else
      g_object_set(renderer, "markup", NULL, "text", "not important", NULL);
    ...
  }

  ...
@end verbatim

Another thing to keep in mind when using pango markup text is that you might
need to escape text if you construct strings with pango markup on the fly using
random input data. For example:

@verbatim
  ...

  void
  foo_cell_data_function ( ... )
  {
    gchar *markuptxt;

    ...
    /* This might be problematic if artist_string or title_string
     *   contain markup characters/entities: */
    markuptxt = g_strdup_printf("<b>%s</b> - <i>%s</i>",
                                artist_string, title_string);
    ...
    g_object_set(renderer, "markup", markuptxt, "text", NULL, NULL);
    ...
    g_free(markuptxt);
  }

  ...
@end verbatim

The above example will not work if artist_string is "Simon & Garfunkel" for
example, because the & character is one of the characters that is special.  They
need to be escaped, so that pango knows that they do not refer to any pango
markup, but are just characters.  In this case the string would need to be
"Simon &amp; Garfunkel" in order to make sense in between the pango markup in
which it is going to be pasted.  You can escape a string with
@code{g_markup_escape} (and you will need to free the resulting newly-allocated
string again with @code{g_free}).

It is possible to combine both pango markup and text cell renderer properties.
Both will be 'added' together to render the string in question, only that the
text cell renderer properties will be applied to the whole string. If you set
the @code{"markup"} property to normal text without any pango markup, it will
render as normal text just as if you had used the @code{"text"} property.
However, as opposed to the @code{"text"} property, special characters in the
@code{"markup"} property text would still need to be escaped, even if you do not
use pango markup in the text.

@c -----------------------------------------------------------------------------
@subsection A Working Example

Here is our example from the very beginning again (with an additional column
though), only that the contents of the model are rendered properly on the screen
this time.  Both attributes and a cell data function are used for demonstration
purposes.

@verbatim
#include <gtk/gtk.h>

enum
{
  COL_FIRST_NAME = 0,
  COL_LAST_NAME,
  COL_YEAR_BORN,
  NUM_COLS
} ;

static GtkTreeModel *
create_and_fill_model (void)
{
  GtkTreeStore  *treestore;
  GtkTreeIter    toplevel, child;

  treestore = gtk_tree_store_new(NUM_COLS,
                                 G_TYPE_STRING,
                                 G_TYPE_STRING,
                                 G_TYPE_UINT);

  /* Append a top level row and leave it empty */
  gtk_tree_store_append(treestore, &toplevel, NULL);
  gtk_tree_store_set(treestore, &toplevel,
                     COL_FIRST_NAME, "Maria",
                     COL_LAST_NAME, "Incognito",
                     -1);

  /* Append a second top level row, and fill it with some data */
  gtk_tree_store_append(treestore, &toplevel, NULL);
  gtk_tree_store_set(treestore, &toplevel,
                     COL_FIRST_NAME, "Jane",
                     COL_LAST_NAME, "Average",
                     COL_YEAR_BORN, (guint) 1962,
                     -1);

  /* Append a child to the second top level row, and fill in some data */
  gtk_tree_store_append(treestore, &child, &toplevel);
  gtk_tree_store_set(treestore, &child,
                     COL_FIRST_NAME, "Janinita",
                     COL_LAST_NAME, "Average",
                     COL_YEAR_BORN, (guint) 1985,
                     -1);

  return GTK_TREE_MODEL(treestore);
}

void
age_cell_data_func (GtkTreeViewColumn *col,
                    GtkCellRenderer   *renderer,
                    GtkTreeModel      *model,
                    GtkTreeIter       *iter,
                    gpointer           user_data)
{
  guint  year_born;
  guint  year_now = 2003; /* to save code not relevant for the example */
  gchar  buf[64];

  gtk_tree_model_get(model, iter, COL_YEAR_BORN, &year_born, -1);

  if (year_born <= year_now && year_born > 0)
  {
    guint age = year_now - year_born;

    g_snprintf(buf, sizeof(buf), "%u years old", age);
    /* print this normal */
    g_object_set(renderer, "foreground-set", FALSE, NULL);
  }
  else
  {
    g_snprintf(buf, sizeof(buf), "age unknown");

    /* make red */
    g_object_set(renderer, "foreground",
                           "Red", "foreground-set", TRUE, NULL);
  }

  g_object_set(renderer, "text", buf, NULL);
}

static GtkWidget *
create_view_and_model (void)
{
  GtkTreeViewColumn   *col;
  GtkCellRenderer     *renderer;
  GtkWidget           *view;
  GtkTreeModel        *model;

  view = gtk_tree_view_new();

  /* --- Column #1 --- */

  col = gtk_tree_view_column_new();

  gtk_tree_view_column_set_title(col, "First Name");

  /* pack tree view column into tree view */
  gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);

  renderer = gtk_cell_renderer_text_new();

  /* pack cell renderer into tree view column */
  gtk_tree_view_column_pack_start(col, renderer, TRUE);

  /* connect 'text' property of the cell renderer to
   *  model column that contains the first name */
  gtk_tree_view_column_add_attribute(col, renderer, "text", COL_FIRST_NAME);


  /* --- Column #2 --- */

  col = gtk_tree_view_column_new();

  gtk_tree_view_column_set_title(col, "Last Name");

  /* pack tree view column into tree view */
  gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);

  renderer = gtk_cell_renderer_text_new();

  /* pack cell renderer into tree view column */
  gtk_tree_view_column_pack_start(col, renderer, TRUE);

  /* connect 'text' property of the cell renderer to
   *  model column that contains the last name */
  gtk_tree_view_column_add_attribute(col, renderer, "text", COL_LAST_NAME);

  /* set 'weight' property of the cell renderer to
   *  bold print (we want all last names in bold) */
  g_object_set(renderer,
               "weight", PANGO_WEIGHT_BOLD,
               "weight-set", TRUE,
               NULL);


  /* --- Column #3 --- */

  col = gtk_tree_view_column_new();

  gtk_tree_view_column_set_title(col, "Age");

  /* pack tree view column into tree view */
  gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);

  renderer = gtk_cell_renderer_text_new();

  /* pack cell renderer into tree view column */
  gtk_tree_view_column_pack_start(col, renderer, TRUE);

  /* connect a cell data function */
  gtk_tree_view_column_set_cell_data_func(col,
                                          renderer,
                                          age_cell_data_func,
                                          NULL, NULL);


  model = create_and_fill_model();

  gtk_tree_view_set_model(GTK_TREE_VIEW(view), model);

  g_object_unref(model); /* destroy model automatically with view */

  gtk_tree_selection_set_mode(
      gtk_tree_view_get_selection(GTK_TREE_VIEW(view)),
      GTK_SELECTION_NONE);

  return view;
}

int
main (int argc, char **argv)
{
  GtkWidget *window;
  GtkWidget *view;

  gtk_init(&argc, &argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  g_signal_connect(window, "delete_event", gtk_main_quit, NULL); /* dirty */

  view = create_view_and_model();

  gtk_container_add(GTK_CONTAINER(window), view);

  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}
@end verbatim

@c -----------------------------------------------------------------------------
@subsection How to Make a Whole Row Bold or Coloured

This seems to be a frequently asked question, so it is worth mentioning it here.
You have the two approaches mentioned above: either you use cell data functions,
and check in each whether a particular row should be highlighted in a particular
way (bold, coloured, whatever), and then set the renderer properties accordingly
(and unset them if you want that row to look normal), or you use attributes.
Cell data functions are most likely not the right choice in this case though.

If you only want every second line to have a gray background to make it easier
for the user to see which data belongs to which line in wide tree views, then
you do not have to bother with the stuff mentioned here. Instead just set the
rules hint on the tree view as described in the here, and everything will be
done automatically, in colours that conform to the chosen theme even (unless the
theme disables rule hints, that is).

Otherwise, the most suitable approach for most cases is that you add two columns
to your model, one for the property itself (e. g. a column @code{COL_ROW_COLOR}
of type @code{G_TYPE_STRING}), and one for the boolean flag of the property
(e. g. a column @code{COL_ROW_COLOR_SET} of type @code{G_TYPE_BOOLEAN}).  You
would then connect these columns with the @code{"foreground"} and
@code{"foreground-set"} properties of each renderer.  Now, whenever you set a
row's @code{COL_ROW_COLOR} field to a colour, and set that row's
@code{COL_ROW_COLOR_SET} field to @emph{true}, then this column will be rendered
in the colour of your choice.  If you only want either the default text colour
or one special other colour, you could even achieve the same thing with just one
extra model column: in this case you could just set all renderer's
@code{"foreground"} property to whatever special color you want, and only
connect the @code{COL_ROW_COLOR_SET} column to all renderer's
@code{"foreground-set"} property using attributes.  This works similar with any
other attribute, only that you need to adjust the data type for the property of
course (e. g. @code{"weight"} would take a @code{G_TYPE_INT}, in form of a
@code{PANGO_WEIGHT_FOO} define in this case).

As a general rule, you should not change the text colour or the background
colour of a cell unless you have a really good reason for it.  To quote Havoc
Pennington: "Because colors in GTK+ represent a theme the user has chosen, you
should never set colors purely for aesthetic reasons.  If users don't like GTK+
gray, they can change it themselves to their favorite shade of orange."

@c -----------------------------------------------------------------------------
@subsection How to Pack Icons into the Tree View

So far we have only put text in the tree view.  While everything you need to
know to display icons (in the form of @xurl{gdk-pixbuf}s) has been introduced in
the previous sections, a short example might help to make things clearer.  The
following code will pack an icon and some text into the same tree view column:

@verbatim
  enum
  {
    COL_ICON = 0,
    COL_TEXT,
    NUM_COLS
  };

  GtkListStore *
  create_liststore(void)
  {
    GtkListStore  *store;
    GtkTreeIter    iter;
    GdkPixbuf     *icon;
    GError        *error = NULL;

    store = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING);

    icon = gdk_pixbuf_new_from_file("icon.png", &error);
    if (error)
    {
      g_warning ("Could not load icon: %s\n", error->message);
      g_error_free(error);
      error = NULL;
    }

    gtk_list_store_append(store, &iter);
    gtk_list_store_set(store, &iter,
                       COL_ICON, icon,
                       COL_TEXT, "example",
                       -1);

    return store;
  }

  GtkWidget *
  create_treeview(void)
  {
    GtkTreeModel      *model;
    GtkTreeViewColumn *col;
    GtkCellRenderer   *renderer;
    GtkWidget         *view;

    model = GTK_TREE_MODEL(create_liststore());

    view = gtk_tree_view_new_with_model(model);

    col = gtk_tree_view_column_new();
    gtk_tree_view_column_set_title(col, "Title");

    renderer = gtk_cell_renderer_pixbuf_new();
    gtk_tree_view_column_pack_start(col, renderer, FALSE);
    gtk_tree_view_column_set_attributes(col, renderer,
                                        "pixbuf", COL_ICON,
                                        NULL);

    renderer = gtk_cell_renderer_text_new();
    gtk_tree_view_column_pack_start(col, renderer, TRUE);
    gtk_tree_view_column_set_attributes(col, renderer,
                                        "text", COL_TEXT,
                                        NULL);

    gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);

    gtk_widget_show_all(view);

    return view;
  }
@end verbatim

Note that the tree view will not resize icons for you, but displays them in
their original size.  If you want to display stock icons instead of
@xurl{gdk-pixbuf}s loaded from file, you should have a look at the
@code{"stock-id"} property of @xurl{gtk-cell-renderer-pixbuf} (and your model
column should be of type @code{G_TYPE_STRING}, as all stock IDs are just strings
by which to identify the stock icon).


@c -----------------------------------------------------------------------------
@node Selections Double-Clicks and Context Menus, Sorting, Mapping Data to the Screen
@section Selections, Double-Clicks and Context Menus

@c -----------------------------------------------------------------------------
@node Sorting, Editable Cells, Selections Double-Clicks and Context Menus
@section Sorting

@c -----------------------------------------------------------------------------
@node Editable Cells, Miscellaneous, Sorting
@section Editable Cells

@c -----------------------------------------------------------------------------
@node Miscellaneous, Drag and Drop, Editable Cells
@section Miscellaneous

@c -----------------------------------------------------------------------------
@node Drag and Drop, Writing Custom Models, Miscellaneous
@section Drag and Drop

@c -----------------------------------------------------------------------------
@node Writing Custom Models, Writing Custom Cell Renderers, Drag and Drop
@section Writing Custom Models

@c -----------------------------------------------------------------------------
@node Writing Custom Cell Renderers, , Writing Custom Models
@section Writing Custom Cell Renderers


