56d35fcf620fcd102ad100cbd79e515071a4541a
[hildon] / hildon / hildon-touch-selector.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2005, 2008 Nokia Corporation.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version. or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free
18  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 /**
22  * SECTION:hildon-touch-selector
23  * @short_description: A selector widget with several columns.
24  *
25  * #HildonTouchSelector is a selector widget, that allows users to
26  * select items from one to many predefined lists. It is very similar
27  * to #GtkComboBox, but with several individual pannable
28  * columns. #HildonTouchSelector does not need to be placed in a
29  * #HildonPannableArea (in fact, doing so will prevent panning).
30  *
31  * Normally, you would use #HildonTouchSelector together with a
32  * #HildonPickerDialog activated from a button. For the most common
33  * cases, you should use #HildonPickerButton.
34  *
35  * The contents of each #HildonTouchSelector column are stored in a
36  * #GtkTreeModel. To add a new column to a #HildonTouchSelector, use
37  * hildon_touch_selector_append_column(). If you want to add a
38  * text-only column, without special attributes, use
39  * hildon_touch_selector_append_text_column().
40  *
41  * It is highly recommended that you use only one column
42  * #HildonTouchSelector<!-- -->s.
43  * If you only need a text only, one column selector, you can create it with
44  * hildon_touch_selector_new_text() and populate with
45  * hildon_touch_selector_append_text(), hildon_touch_selector_prepend_text(),
46  * and hildon_touch_selector_insert_text().
47  *
48  * If you need a selector widget that also accepts user inputs, you
49  * can use #HildonTouchSelectorEntry.
50  *
51  * The current selection has a string representation. In the most common cases,
52  * each column model will contain a text column. You can configure
53  * which column in particular using the #HildonTouchSelectorColumn property
54  * #HildonTouchSelectorColumn:text-column
55  *
56  * You can get this string representation using
57  * hildon_touch_selector_get_current_text().
58  * You can configure how the selection is printed with
59  * hildon_touch_selector_set_print_func(), that sets the current hildon touch
60  * selector print function. The widget has a default print function, that
61  * uses the #HildonTouchSelectorColumn:text-column property on each
62  * #HildonTouchSelectorColumn to compose the final representation.
63  *
64  * If you create the selector using hildon_touch_selector_new_text() you
65  * don't need to take care of this property, as the model is created internally.
66  * If you create the selector using hildon_touch_selector_new(), you
67  * need to specify properly the property for your custom model in order to get a
68  * non-empty string representation, or define your custom print function.
69  *
70  * <example>
71  * <title>Creating a HildonTouchSelector</title>
72  * <programlisting>
73  * void
74  * selection_changed (HildonTouchSelector * selector,
75  *                    gpointer *user_data)
76  * {
77  *   gchar *current_selection = NULL;
78  * <!-- -->
79  *   current_selection = hildon_touch_selector_get_current_text (selector);
80  *   g_debug ("Current selection : &percnt;s", current_selection);
81  * }
82  * <!-- -->
83  * static GtkWidget *
84  * create_customized_selector ()
85  * {
86  *   GtkWidget *selector = NULL;
87  *   GSList *icon_list = NULL;
88  *   GtkListStore *store_icons = NULL;
89  *   GSList *item = NULL;
90  *   GtkCellRenderer *renderer = NULL;
91  *   HildonTouchSelectorColumn *column = NULL;
92  * <!-- -->
93  *   selector = hildon_touch_selector_new ();
94  * <!-- -->
95  *   icon_list = gtk_stock_list_ids ();
96  * <!-- -->
97  *   store_icons = gtk_list_store_new (1, G_TYPE_STRING);
98  *   for (item = icon_list; item; item = g_slist_next (item)) {
99  *     GtkTreeIter iter;
100  *     gchar *label = item->data;
101  * <!-- -->
102  *     gtk_list_store_append (store_icons, &amp;iter);
103  *     gtk_list_store_set (store_icons, &amp;iter, 0, label, -1);
104  *     g_free (label);
105  *   }
106  *   g_slist_free (icon_list);
107  * <!-- -->
108  *   renderer = gtk_cell_renderer_pixbuf_new ();
109  *   gtk_cell_renderer_set_fixed_size (renderer, -1, 100);
110  * <!-- -->
111  *   column = hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector),
112  *                                                 GTK_TREE_MODEL (store_icons),
113  *                                                 renderer, "stock-id", 0, NULL);
114  * <!-- -->
115  *   hildon_touch_selector_column_set_text_column (column, 0);
116  * <!-- -->
117  *   hildon_touch_selector_set_column_selection_mode (HILDON_TOUCH_SELECTOR (selector),
118  *                                                    HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE);
119  * <!-- -->
120  *   g_signal_connect (G_OBJECT (selector), "changed",
121  *                     G_CALLBACK (selection_changed), NULL);
122  * <!-- -->
123  *   return selector;
124  * }
125  * <!-- -->
126  * static GtkWidget *
127  * create_simple_selector ()
128  * {
129  *   GtkWidget *selector = NULL;
130  *   gint i;
131  * <!-- -->
132  *   selector = hildon_touch_selector_new_text ();
133  *   hildon_touch_selector_set_column_selection_mode (HILDON_TOUCH_SELECTOR (selector),
134  *                                                    HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE);
135  * <!-- -->
136  *   g_signal_connect (G_OBJECT (selector), "changed",
137  *                     G_CALLBACK (selection_changed), NULL);
138  * <!-- -->
139  *   for (i = 1; i <= 10 ; i++) {
140  *     gchar *label = g_strdup_printf ("Item &amp;percnt;d", i);
141  * <!-- -->
142  *     hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (selector),
143  *                                        label);
144  * <!-- -->
145  *     g_free (label);
146  *   }
147  * <!-- -->
148  *   return selector;
149  * }
150  * </programlisting>
151  * </example>
152  */
153
154 /**
155  * SECTION:hildon-touch-selector-column
156  * @short_description: A visible column in a #HildonTouchSelector
157  * @see_also: #HildonTouchSelector
158  *
159  * A #HildonTouchSelectorColumn is a column in a
160  * #HildonTouchSelector. This class implements the #GtkCellLayout interface, allowing
161  * a flexible management of the cellrenderers in each #HildonTouchSelector column.
162  */
163
164 #undef HILDON_DISABLE_DEPRECATED
165
166 #ifdef HAVE_CONFIG_H
167 #include <config.h>
168 #endif
169
170 #include <string.h>
171 #include <stdlib.h>
172
173 #include "hildon-gtk.h"
174
175 #include "hildon-pannable-area.h"
176 #include "hildon-touch-selector.h"
177 #include "hildon-touch-selector-private.h"
178
179 #define HILDON_TOUCH_SELECTOR_GET_PRIVATE(obj)                          \
180   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), HILDON_TYPE_TOUCH_SELECTOR, HildonTouchSelectorPrivate))
181
182 G_DEFINE_TYPE (HildonTouchSelector, hildon_touch_selector, GTK_TYPE_VBOX)
183
184 /*
185  * IMPLEMENTATION NOTES:
186  * Struct to maintain the data of each column. The columns are the elements
187  * of the widget that belongs properly to the selection behaviour. Although
188  * internally the columns are arranged in a private #GtkHBox, as the selector
189  * itself is a #GtkVBox, you can add more widgets, like buttons etc., so
190  * you finally could have a widget with more elements that the columns, but
191  * this doesn't belongs to the selection logic
192  */
193 struct _HildonTouchSelectorColumnPrivate
194 {
195   HildonTouchSelector *parent;    /* the selector that contains this column */
196   GtkTreeModel *model;
197   gint text_column;
198   GtkTreeView *tree_view;
199   gulong realize_handler;
200   GtkTreePath *initial_path;
201
202   GtkWidget *panarea;           /* the pannable widget */
203   GtkTreeRowReference *last_activated;
204 };
205
206 struct _HildonTouchSelectorPrivate
207 {
208   GSList *columns;              /* the selection columns */
209   GtkWidget *hbox;              /* the container for the selector's columns */
210   gboolean initial_scroll;      /* whether initial fancy scrolling to selection */
211
212   gboolean changed_blocked;
213
214   HildonTouchSelectorPrintFunc print_func;
215   gpointer print_user_data;
216   GDestroyNotify print_destroy_func;
217
218   HildonUIMode hildon_ui_mode;
219 };
220
221 enum
222 {
223   PROP_HAS_MULTIPLE_SELECTION = 1,
224   PROP_INITIAL_SCROLL,
225   PROP_HILDON_UI_MODE
226 };
227
228 enum
229 {
230   CHANGED,
231   COLUMNS_CHANGED,
232   LAST_SIGNAL
233 };
234
235 static gint hildon_touch_selector_signals[LAST_SIGNAL] = { 0 };
236
237 static void
238 hildon_touch_selector_dispose                   (GObject * object);
239
240 static void
241 hildon_touch_selector_get_property              (GObject * object,
242                                                  guint prop_id,
243                                                  GValue * value,
244                                                  GParamSpec * pspec);
245 static void
246 hildon_touch_selector_set_property              (GObject *object,
247                                                  guint prop_id,
248                                                  const GValue *value,
249                                                  GParamSpec *pspec);
250 /* gtkwidget */
251
252 /* gtkcontainer */
253 static void hildon_touch_selector_remove        (GtkContainer * container,
254                                                  GtkWidget * widget);
255 /* private functions */
256 static void _row_tapped_cb                      (GtkTreeView * tree_view,
257                                                  GtkTreePath * path,
258                                                  gpointer user_data);
259 static void
260 hildon_touch_selector_row_activated_cb          (GtkTreeView       *tree_view,
261                                                  GtkTreePath       *path,
262                                                  GtkTreeViewColumn *column,
263                                                  gpointer           user_data);
264
265 static gchar *_default_print_func               (HildonTouchSelector * selector,
266                                                  gpointer user_data);
267
268 static HildonTouchSelectorColumn *_create_new_column (HildonTouchSelector * selector,
269                                                  GtkTreeModel * model,
270                                                  gboolean *emit_changed,
271                                                  GtkCellRenderer * renderer,
272                                                  va_list args);
273 static gboolean
274 on_realize_cb                                  (GtkWidget *widget,
275                                                 gpointer data);
276 static void
277 on_row_changed                                 (GtkTreeModel *model,
278                                                 GtkTreePath *path,
279                                                 GtkTreeIter *iter,
280                                                 gpointer userdata);
281
282 static void
283 hildon_touch_selector_scroll_to (HildonTouchSelectorColumn *column,
284                                  GtkTreeView *tv,
285                                  GtkTreePath *path);
286 static gboolean
287 _hildon_touch_selector_center_on_selected_items (HildonTouchSelector *selector,
288                                                  HildonTouchSelectorColumn *column);
289 static void
290 _hildon_touch_selector_set_model                (HildonTouchSelector * selector,
291                                                  gint num_column,
292                                                  GtkTreeModel * model);
293 static gboolean
294 _hildon_touch_selector_has_multiple_selection   (HildonTouchSelector * selector);
295
296 static void
297 hildon_touch_selector_emit_value_changed        (HildonTouchSelector *selector,
298                                                  gint column);
299
300 /* GtkCellLayout implementation (HildonTouchSelectorColumn)*/
301 static void hildon_touch_selector_column_cell_layout_init         (GtkCellLayoutIface      *iface);
302
303 static void hildon_touch_selector_column_cell_layout_pack_start   (GtkCellLayout         *cell_layout,
304                                                                    GtkCellRenderer       *cell,
305                                                                    gboolean               expand);
306 static void hildon_touch_selector_column_cell_layout_pack_end     (GtkCellLayout         *cell_layout,
307                                                                    GtkCellRenderer       *cell,
308                                                                    gboolean               expand);
309 static void hildon_touch_selector_column_cell_layout_clear        (GtkCellLayout         *cell_layout);
310 static void hildon_touch_selector_column_cell_layout_add_attribute(GtkCellLayout         *cell_layout,
311                                                                    GtkCellRenderer       *cell,
312                                                                    const gchar           *attribute,
313                                                                    gint                   column);
314 static void hildon_touch_selector_column_cell_layout_set_cell_data_func (GtkCellLayout         *cell_layout,
315                                                                          GtkCellRenderer       *cell,
316                                                                          GtkCellLayoutDataFunc  func,
317                                                                          gpointer               func_data,
318                                                                          GDestroyNotify         destroy);
319 static void hildon_touch_selector_column_cell_layout_clear_attributes   (GtkCellLayout         *cell_layout,
320                                                                          GtkCellRenderer       *cell);
321 static void hildon_touch_selector_column_cell_layout_reorder       (GtkCellLayout         *cell_layout,
322                                                                     GtkCellRenderer       *cell,
323                                                                     gint                   position);
324 static GList *hildon_touch_selector_column_cell_layout_get_cells   (GtkCellLayout         *cell_layout);
325
326 static void
327 hildon_touch_selector_check_ui_mode_coherence   (HildonTouchSelector *selector);
328
329 static void
330 hildon_touch_selector_class_init (HildonTouchSelectorClass * class)
331 {
332   GObjectClass *gobject_class;
333   GtkObjectClass *object_class;
334   GtkContainerClass *container_class;
335
336   gobject_class = G_OBJECT_CLASS (class);
337   object_class = GTK_OBJECT_CLASS (class);
338   container_class = GTK_CONTAINER_CLASS (class);
339
340   /* GObject */
341   gobject_class->dispose = hildon_touch_selector_dispose;
342   gobject_class->get_property = hildon_touch_selector_get_property;
343   gobject_class->set_property = hildon_touch_selector_set_property;
344
345   /* GtkWidget */
346
347   /* GtkContainer */
348   container_class->remove = hildon_touch_selector_remove;
349
350   /* HildonTouchSelector */
351   class->changed = NULL;
352   class->set_model = _hildon_touch_selector_set_model;
353
354   class->has_multiple_selection = _hildon_touch_selector_has_multiple_selection;
355
356   /* signals */
357   /**
358    * HildonTouchSelector::changed:
359    * @widget: the object which received the signal
360    * @column: the number of the column that has changed
361    *
362    * The "changed" signal is emitted when the active item on any column is changed.
363    * This can be due to the user selecting a different item from the list, or
364    * due to a call to hildon_touch_selector_select_iter() on one of the columns.
365    *
366    * Since: 2.2
367    */
368   hildon_touch_selector_signals[CHANGED] =
369     g_signal_new ("changed",
370                   G_OBJECT_CLASS_TYPE (class),
371                   G_SIGNAL_RUN_LAST,
372                   G_STRUCT_OFFSET (HildonTouchSelectorClass, changed),
373                   NULL, NULL,
374                   g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
375
376   /**
377    * HildonTouchSelector::columns-changed:
378    * @selector: the object which received the signal
379    *
380    * The "columns-changed" signal is emitted when the number
381    * of columns in the #HildonTouchSelector change.
382    *
383    * Since: 2.2
384    */
385   hildon_touch_selector_signals[COLUMNS_CHANGED] =
386     g_signal_new ("columns-changed",
387                   G_OBJECT_CLASS_TYPE (class),
388                   G_SIGNAL_RUN_LAST, 0,
389                   NULL, NULL,
390                   g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
391
392   /* properties */
393
394   g_object_class_install_property (gobject_class, PROP_HAS_MULTIPLE_SELECTION,
395                                    g_param_spec_boolean ("has-multiple-selection",
396                                                          "has multiple selection",
397                                                          "Whether the widget has multiple "
398                                                          "selection (like multiple columns, "
399                                                          "multiselection mode, or multiple "
400                                                          "internal widgets) and therefore "
401                                                          "it may need a confirmation button, "
402                                                          "for instance.",
403                                                          FALSE,
404                                                          G_PARAM_READABLE));
405
406   g_object_class_install_property (G_OBJECT_CLASS (gobject_class),
407                                    PROP_INITIAL_SCROLL,
408                                    g_param_spec_boolean ("initial-scroll",
409                                                          "Initial scroll",
410                                                          "Whether to scroll to the"
411                                                          "current selection when"
412                                                          "the selector is first"
413                                                          "shown",
414                                                          TRUE,
415                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
416
417     /**
418      * HildonTouchSelector:hildon-ui-mode:
419      *
420      * Specifies which UI mode to use in the internal treeviews.  A setting
421      * of %HILDON_UI_MODE_NORMAL will cause these tree view to disable selections
422      * and emit row-activated as soon as a row is pressed.  You can use the
423      * method hildon_touch_selector_get_last_activated_row() to get it. When
424      * %HILDON_UI_MODE_EDIT is set, selections can be made according to the
425      * setting of the mode on GtkTreeSelection.
426      *
427      * Toggling this property will cause the tree view to select an
428      * appropriate selection mode if not already done.
429      *
430      * Since: Hildon 2.2
431      */
432   g_object_class_install_property (gobject_class,
433                                    PROP_HILDON_UI_MODE,
434                                    g_param_spec_enum ("hildon-ui-mode",
435                                                       "Hildon UI Mode",
436                                                       "The Hildon UI mode according "
437                                                       "to which the touch selector "
438                                                       "should behave",
439                                                       HILDON_TYPE_UI_MODE,
440                                                       HILDON_UI_MODE_EDIT,
441                                                       G_PARAM_READWRITE));
442   /* style properties */
443   /* We need to ensure fremantle mode for the treeview in order to work
444      properly. This is not about the appearance, this is about behaviour */
445   gtk_rc_parse_string ("style \"fremantle-htst\" {\n"
446                        "  GtkWidget::hildon-mode = 1\n"
447                        "} widget \"*.fremantle-htst\" style \"fremantle-htst\""
448                        "widget_class \"*<HildonPannableArea>.GtkTreeView\" style :highest \"fremantle-htst\"");
449
450   g_type_class_add_private (object_class, sizeof (HildonTouchSelectorPrivate));
451 }
452
453 static void
454 hildon_touch_selector_get_property (GObject * object,
455                                     guint prop_id,
456                                     GValue * value, GParamSpec * pspec)
457 {
458   HildonTouchSelectorPrivate *priv = HILDON_TOUCH_SELECTOR (object)->priv;
459
460   switch (prop_id) {
461   case PROP_HAS_MULTIPLE_SELECTION:
462     g_value_set_boolean (value,
463                          hildon_touch_selector_has_multiple_selection (HILDON_TOUCH_SELECTOR (object)));
464     break;
465   case PROP_INITIAL_SCROLL:
466     g_value_set_boolean (value, priv->initial_scroll);
467     break;
468   case PROP_HILDON_UI_MODE:
469     g_value_set_enum (value, priv->hildon_ui_mode);
470     break;
471   default:
472     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
473     break;
474   }
475 }
476
477 static void
478 hildon_touch_selector_set_property (GObject *object, guint prop_id,
479                                     const GValue *value, GParamSpec *pspec)
480 {
481   HildonTouchSelectorPrivate *priv = HILDON_TOUCH_SELECTOR (object)->priv;
482
483   switch (prop_id) {
484   case PROP_INITIAL_SCROLL:
485     priv->initial_scroll = g_value_get_boolean (value);
486     break;
487   case PROP_HILDON_UI_MODE:
488     hildon_touch_selector_set_hildon_ui_mode (HILDON_TOUCH_SELECTOR (object),
489                                               g_value_get_enum (value));
490     break;
491   default:
492     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
493     break;
494   }
495 }
496
497
498 static void
499 hildon_touch_selector_init (HildonTouchSelector * selector)
500 {
501   selector->priv = HILDON_TOUCH_SELECTOR_GET_PRIVATE (selector);
502
503   GTK_WIDGET_SET_FLAGS (GTK_WIDGET (selector), GTK_NO_WINDOW);
504   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (selector), FALSE);
505
506   selector->priv->columns = NULL;
507
508   selector->priv->print_func = NULL;
509   selector->priv->print_user_data = NULL;
510   selector->priv->print_destroy_func = NULL;
511   selector->priv->initial_scroll = TRUE;
512   selector->priv->hbox = gtk_hbox_new (FALSE, 0);
513
514   selector->priv->changed_blocked = FALSE;
515
516   selector->priv->hildon_ui_mode = HILDON_UI_MODE_EDIT;
517
518   gtk_box_pack_end (GTK_BOX (selector), selector->priv->hbox,
519                     TRUE, TRUE, 0);
520   gtk_widget_show (selector->priv->hbox);
521 }
522
523 static void
524 hildon_touch_selector_dispose (GObject * object)
525 {
526   GObjectClass *gobject_class;
527
528   hildon_touch_selector_set_print_func_full (HILDON_TOUCH_SELECTOR (object),
529                                              NULL, NULL, NULL);
530
531   gobject_class = G_OBJECT_CLASS (hildon_touch_selector_parent_class);
532
533   if (gobject_class->dispose)
534     (* gobject_class->dispose) (object);
535 }
536
537 static void
538 clean_column                                    (HildonTouchSelectorColumn *col,
539                                                  HildonTouchSelector *selector)
540 {
541   g_signal_handlers_disconnect_by_func (col->priv->model,
542                                         on_row_changed, selector);
543
544   if (col->priv->last_activated != NULL) {
545     gtk_tree_row_reference_free (col->priv->last_activated);
546     col->priv->last_activated = NULL;
547   }
548 }
549
550 /*
551  * IMPLEMENTATION NOTES:
552  * Some people sent questions regarding the fact that the dispose/finalize functions
553  * doesn't clean the internal widgets that could lead to leak memory, so we will
554  * clarify this topic.
555  *
556  * This is not required as #HildonTouchSelector extends #GtkContainer. When the
557  * widget is freed, the #GtkContainer freeing memory functions are called. This
558  * process includes remove each widget individually, so all the widgets are
559  * properly freed.
560  *
561  * In the same way, this widget redefines gtk_container->remove function, in
562  * order to free the column related information if it is required.
563  *
564  * Please take a look to hildon_touch_selector_remove for more information.
565  */
566
567 /*------------------------------ GtkContainer ------------------------------ */
568
569 /*
570  * Required in order to free the column at the columns list
571  */
572 static void
573 hildon_touch_selector_remove (GtkContainer * container, GtkWidget * widget)
574 {
575   HildonTouchSelector *selector = NULL;
576
577   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (container));
578   selector = HILDON_TOUCH_SELECTOR (container);
579
580   /* Remove the extra data related to the columns, if required. */
581   if (widget == selector->priv->hbox) {
582     g_slist_foreach (selector->priv->columns, (GFunc) clean_column, selector);
583     g_slist_foreach (selector->priv->columns, (GFunc) g_object_unref, NULL);
584
585     g_slist_free (selector->priv->columns);
586
587     selector->priv->columns = NULL;
588   } else {
589     g_debug ("Freeing a widget outside the columns logic");
590   }
591
592   /* Now remove the widget itself from the container */
593   GTK_CONTAINER_CLASS (hildon_touch_selector_parent_class)->remove (container, widget);
594 }
595
596 /* ------------------------------ PRIVATE METHODS ---------------------------- */
597 void
598 hildon_touch_selector_block_changed             (HildonTouchSelector *selector)
599 {
600   selector->priv->changed_blocked = TRUE;
601 }
602
603 void
604 hildon_touch_selector_unblock_changed           (HildonTouchSelector *selector)
605 {
606   selector->priv->changed_blocked = FALSE;
607 }
608
609 static void
610 hildon_touch_selector_emit_value_changed        (HildonTouchSelector *selector,
611                                                  gint column)
612 {
613   /* FIXME: it could be good to emit too the GtkTreePath of the element
614      selected, as now it is required to connect to the signal and then ask
615      for the element selected. We can't do this API change, in order to avoid
616      and ABI break */
617   if (!selector->priv->changed_blocked) {
618     g_signal_emit (selector, hildon_touch_selector_signals[CHANGED], 0, column);
619   }
620 }
621
622 static void
623 hildon_touch_selector_check_ui_mode_coherence   (HildonTouchSelector *selector)
624 {
625   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
626
627   if (hildon_touch_selector_get_num_columns (selector) > 1) {
628     hildon_touch_selector_set_hildon_ui_mode (selector, HILDON_UI_MODE_EDIT);
629   }
630 }
631
632 /**
633  * default_print_func:
634  * @selector: a #HildonTouchSelector
635  *
636  * Default print function
637  *
638  * Returns: a new string that represents the selected items
639  *
640  * Since: 2.2
641  **/
642 static gchar *
643 _default_print_func (HildonTouchSelector * selector, gpointer user_data)
644 {
645   gchar *result = NULL;
646   gchar *aux = NULL;
647   gint num_columns = 0;
648   GtkTreeIter iter;
649   GtkTreeModel *model = NULL;
650   gchar *current_string = NULL;
651   gint i;
652   HildonTouchSelectorSelectionMode mode;
653   GList *item = NULL;
654   GtkTreePath *current_path = NULL;
655   GList *selected_rows = NULL;
656   gint initial_value = 0;
657   gint text_column = -1;
658   HildonTouchSelectorColumn *column = NULL;
659
660   num_columns = hildon_touch_selector_get_num_columns (selector);
661
662   mode = hildon_touch_selector_get_column_selection_mode (selector);
663
664   if ((mode == HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE)
665       && (num_columns > 0)) {
666     /* In this case we get the first column first */
667     selected_rows = hildon_touch_selector_get_selected_rows (selector, 0);
668     model = hildon_touch_selector_get_model (selector, 0);
669     column = hildon_touch_selector_get_column (selector, 0);
670     text_column = hildon_touch_selector_column_get_text_column (column);
671
672     result = g_strdup_printf ("(");
673     i = 0;
674     for (item = selected_rows; item; item = g_list_next (item)) {
675       current_path = item->data;
676       gtk_tree_model_get_iter (model, &iter, current_path);
677
678       if (text_column != -1) {
679         gtk_tree_model_get (model, &iter, text_column, &current_string, -1);
680       }
681
682       if (i < g_list_length (selected_rows) - 1) {
683         aux = g_strconcat (result, current_string, ",", NULL);
684         g_free (result);
685         result = aux;
686       } else {
687         aux = g_strconcat (result, current_string, NULL);
688         g_free (result);
689         result = aux;
690       }
691
692       if (current_string) {
693         g_free (current_string);
694         current_string = NULL;
695       }
696
697       i++;
698     }
699
700     aux = g_strconcat (result, ")", NULL);
701     g_free (result);
702     result = aux;
703
704     g_list_foreach (selected_rows, (GFunc) (gtk_tree_path_free), NULL);
705     g_list_free (selected_rows);
706     initial_value = 1;
707   } else {
708     initial_value = 0;
709   }
710
711   for (i = initial_value; i < num_columns; i++) {
712     model = hildon_touch_selector_get_model (selector, i);
713     column = hildon_touch_selector_get_column (selector, i);
714     text_column = hildon_touch_selector_column_get_text_column (column);
715
716     if (hildon_touch_selector_get_selected (selector, i, &iter)) {
717       if (text_column == -1 ) {
718         g_warning ("Trying to use the default print function in HildonTouchSelector, but "
719                    "\"text-column\" property is not set for HildonTouchSelectorColumn %p.", column);
720         current_string = NULL;
721       } else {
722         gtk_tree_model_get (model, &iter, text_column, &current_string, -1);
723       }
724
725       if (i == 0) {
726         result = current_string;
727       } else {
728         aux = g_strconcat (result, ":", current_string, NULL);
729         g_free (result);
730         g_free (current_string);
731         current_string = NULL;
732         result = aux;
733       }
734     }
735   }
736
737   return result;
738 }
739
740 static void
741 hildon_touch_selector_row_activated_cb          (GtkTreeView       *tree_view,
742                                                  GtkTreePath       *path,
743                                                  GtkTreeViewColumn *column,
744                                                  gpointer           user_data)
745 {
746   HildonTouchSelectorColumn *selector_column = NULL;
747   GtkTreeModel *model = NULL;
748
749   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (user_data));
750   selector_column = HILDON_TOUCH_SELECTOR_COLUMN (user_data);
751
752   model = selector_column->priv->model;
753
754   if (selector_column->priv->last_activated != NULL) {
755     gtk_tree_row_reference_free (selector_column->priv->last_activated);
756   }
757
758   selector_column->priv->last_activated = gtk_tree_row_reference_new (model, path);
759 }
760
761 static void
762 _row_tapped_cb (GtkTreeView * tree_view, GtkTreePath * path, gpointer user_data)
763 {
764   HildonTouchSelector *selector = NULL;
765   HildonTouchSelectorColumn *column = NULL;
766   gint num_column = -1;
767
768   column = HILDON_TOUCH_SELECTOR_COLUMN (user_data);
769   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (column->priv->parent));
770
771   selector = column->priv->parent;
772
773   num_column = g_slist_index (selector->priv->columns, column);
774
775   hildon_touch_selector_emit_value_changed (selector, num_column);
776 }
777
778
779 static HildonTouchSelectorColumn *
780 _create_new_column (HildonTouchSelector * selector,
781                     GtkTreeModel * model,
782                     gboolean *emit_changed,
783                     GtkCellRenderer * renderer, va_list args)
784 {
785   HildonTouchSelectorColumn *new_column = NULL;
786   GtkTreeViewColumn *tree_column = NULL;
787   GtkTreeView *tv = NULL;
788   GtkWidget *panarea = NULL;
789   GtkTreeSelection *selection = NULL;
790   GtkTreeIter iter;
791   gchar *attribute;
792   gint value;
793
794   tree_column = gtk_tree_view_column_new ();
795
796   if (renderer != NULL) {
797     gtk_tree_view_column_pack_start (tree_column, renderer, TRUE);
798
799     attribute = va_arg (args, gchar *);
800     while (attribute != NULL) {
801       value = va_arg (args, gint);
802       gtk_tree_view_column_add_attribute (tree_column, renderer, attribute,
803                                           value);
804       attribute = va_arg (args, gchar *);
805     }
806   }
807
808 #ifdef MAEMO_GTK
809   tv = GTK_TREE_VIEW (hildon_gtk_tree_view_new (selector->priv->hildon_ui_mode));
810 #else
811   tv = GTK_TREE_VIEW (gtk_tree_view_new ());
812 #endif /* MAEMO_GTK */
813
814   gtk_tree_view_set_enable_search (tv, FALSE);
815   GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (tv), GTK_CAN_FOCUS);
816
817   gtk_tree_view_set_model (tv, model);
818   g_signal_connect (model, "row-changed",
819                     G_CALLBACK (on_row_changed), selector);
820   gtk_tree_view_set_rules_hint (tv, TRUE);
821
822   gtk_tree_view_append_column (GTK_TREE_VIEW (tv), tree_column);
823
824   new_column = g_object_new (HILDON_TYPE_TOUCH_SELECTOR_COLUMN, NULL);
825   new_column->priv->parent = selector;
826
827   panarea = hildon_pannable_area_new ();
828
829   g_object_set (G_OBJECT (panarea),
830                 "initial-hint", FALSE, NULL);
831
832   gtk_container_add (GTK_CONTAINER (panarea), GTK_WIDGET (tv));
833
834   new_column->priv->model = model;
835   new_column->priv->tree_view = tv;
836   new_column->priv->panarea = panarea;
837   new_column->priv->realize_handler = 0;
838   new_column->priv->initial_path = NULL;
839
840   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
841   gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
842
843   /* select the first item */
844   *emit_changed = FALSE;
845   if ((gtk_tree_model_get_iter_first (model, &iter))&&
846       (selector->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT)) {
847     gtk_tree_selection_select_iter (selection, &iter);
848     *emit_changed = TRUE;
849   }
850
851   gtk_widget_grab_focus (GTK_WIDGET (tv));
852
853   /* connect to the hildon-row-tapped signal connection */
854   g_signal_connect (G_OBJECT (tv), "hildon-row-tapped",
855                     G_CALLBACK (_row_tapped_cb), new_column);
856
857   g_signal_connect (G_OBJECT (tv), "row-activated",
858                     G_CALLBACK (hildon_touch_selector_row_activated_cb), new_column);
859
860   return new_column;
861 }
862
863
864 /* ------------------------ HildonTouchSelectorColumn implementation ---------------------- */
865 G_DEFINE_TYPE_WITH_CODE (HildonTouchSelectorColumn, hildon_touch_selector_column, G_TYPE_OBJECT,
866                          G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
867                                                 hildon_touch_selector_column_cell_layout_init))
868
869 enum
870 {
871   PROP_TEXT_COLUMN = 1
872 };
873
874 static void
875 hildon_touch_selector_column_class_init (HildonTouchSelectorColumnClass *klass);
876
877 static void
878 hildon_touch_selector_column_get_property (GObject *object, guint property_id,
879                                            GValue *value, GParamSpec *pspec);
880
881 static void
882 hildon_touch_selector_column_set_property  (GObject *object, guint property_id,
883                                             const GValue *value, GParamSpec *pspec);
884
885
886 static void
887 hildon_touch_selector_column_class_init (HildonTouchSelectorColumnClass *klass)
888 {
889   GObjectClass *gobject_class = NULL;
890
891   gobject_class = G_OBJECT_CLASS (klass);
892
893   g_type_class_add_private (gobject_class, sizeof (HildonTouchSelectorColumnPrivate));
894
895   /* GObject */
896   gobject_class->get_property = hildon_touch_selector_column_get_property;
897   gobject_class->set_property = hildon_touch_selector_column_set_property;
898
899   /**
900    * HildonTouchSelectorColumn:text-column:
901    *
902    * A column in the data source model to get the strings from.
903    *
904    * Since: maemo 2.2
905    **/
906   g_object_class_install_property (G_OBJECT_CLASS(klass),
907                                    PROP_TEXT_COLUMN,
908                                    g_param_spec_int ("text-column",
909                                                      "Text Column",
910                                                      "A column in the data source model to get the strings from.",
911                                                      -1,
912                                                      G_MAXINT,
913                                                      -1,
914                                                      G_PARAM_READWRITE));
915 }
916
917 static void
918 hildon_touch_selector_column_init (HildonTouchSelectorColumn *column)
919 {
920   column->priv = G_TYPE_INSTANCE_GET_PRIVATE (column, HILDON_TYPE_TOUCH_SELECTOR_COLUMN,
921                                               HildonTouchSelectorColumnPrivate);
922   column->priv->text_column = -1;
923   column->priv->last_activated = NULL;
924 }
925
926 /**
927  * hildon_touch_selector_column_set_text_column:
928  * @column: A #HildonTouchSelectorColumn
929  * @text_column: the index of a model column in the model for @column.
930  *
931  * Sets the model column to be displayed in @column. @text_column must point to a
932  * column in the model used with type %G_TYPE_STRING. Initially, this property
933  * is unset. You should set it before using the #HildonTouchSelector that uses
934  * @column.
935  *
936  * Since: 2.2
937  **/
938 void
939 hildon_touch_selector_column_set_text_column (HildonTouchSelectorColumn *column,
940                                               gint text_column)
941 {
942   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (column));
943   g_return_if_fail (text_column >= -1);
944
945   column->priv->text_column = text_column;
946
947   g_object_notify (G_OBJECT (column), "text-column");
948 }
949
950 /**
951  * hildon_touch_selector_column_get_text_column:
952  * @column: a #HildonTouchSelectorColumn
953  *
954  * Gets the model column set as the text source for @column.
955  *
956  * Returns: the index of the text column for @column, or -1 if unset.
957  *
958  * Since: 2.2
959  **/
960 gint
961 hildon_touch_selector_column_get_text_column (HildonTouchSelectorColumn *column)
962 {
963   g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (column), -1);
964
965   return column->priv->text_column;
966 }
967
968 static void
969 hildon_touch_selector_column_get_property (GObject *object, guint property_id,
970                                            GValue *value, GParamSpec *pspec)
971 {
972   switch (property_id) {
973   case PROP_TEXT_COLUMN:
974     g_value_set_int (value,
975                      hildon_touch_selector_column_get_text_column (HILDON_TOUCH_SELECTOR_COLUMN (object)));
976     break;
977   default:
978     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
979   }
980 }
981
982 static void
983 hildon_touch_selector_column_set_property (GObject *object, guint property_id,
984                                            const GValue *value, GParamSpec *pspec)
985 {
986   switch (property_id) {
987   case PROP_TEXT_COLUMN:
988     hildon_touch_selector_column_set_text_column (HILDON_TOUCH_SELECTOR_COLUMN (object),
989                                                   g_value_get_int (value));
990     break;
991   default:
992     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
993   }
994 }
995
996 /* ------------------------ GtkCellLayout implementation -------------------- */
997 static void
998 hildon_touch_selector_column_cell_layout_init (GtkCellLayoutIface      *iface)
999 {
1000   iface->pack_start         = hildon_touch_selector_column_cell_layout_pack_start;
1001   iface->pack_end           = hildon_touch_selector_column_cell_layout_pack_end;
1002   iface->clear              = hildon_touch_selector_column_cell_layout_clear;
1003   iface->add_attribute      = hildon_touch_selector_column_cell_layout_add_attribute;
1004   iface->set_cell_data_func = hildon_touch_selector_column_cell_layout_set_cell_data_func;
1005   iface->clear_attributes   = hildon_touch_selector_column_cell_layout_clear_attributes;
1006   iface->reorder            = hildon_touch_selector_column_cell_layout_reorder;
1007   iface->get_cells          = hildon_touch_selector_column_cell_layout_get_cells;
1008 }
1009
1010 static void
1011 hildon_touch_selector_column_cell_layout_pack_start (GtkCellLayout         *cell_layout,
1012                                                GtkCellRenderer       *cell,
1013                                                gboolean               expand)
1014 {
1015   HildonTouchSelectorColumn *sel_column = NULL;
1016   GtkTreeViewColumn *view_column = NULL;
1017
1018   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (cell_layout));
1019   sel_column = HILDON_TOUCH_SELECTOR_COLUMN (cell_layout);
1020
1021   view_column = gtk_tree_view_get_column (sel_column->priv->tree_view, 0);
1022
1023   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(view_column), cell, expand);
1024
1025 }
1026
1027 static void
1028 hildon_touch_selector_column_cell_layout_pack_end (GtkCellLayout         *cell_layout,
1029                                              GtkCellRenderer       *cell,
1030                                              gboolean               expand)
1031 {
1032   HildonTouchSelectorColumn *sel_column = NULL;
1033   GtkTreeViewColumn *view_column = NULL;
1034
1035   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (cell_layout));
1036   sel_column = HILDON_TOUCH_SELECTOR_COLUMN (cell_layout);
1037
1038   view_column = gtk_tree_view_get_column (sel_column->priv->tree_view, 0);
1039
1040   gtk_cell_layout_pack_end (GTK_CELL_LAYOUT(view_column), cell, expand);
1041 }
1042
1043 static void
1044 hildon_touch_selector_column_cell_layout_clear (GtkCellLayout         *cell_layout)
1045 {
1046   HildonTouchSelectorColumn *sel_column = NULL;
1047   GtkTreeViewColumn *view_column = NULL;
1048
1049   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (cell_layout));
1050   sel_column = HILDON_TOUCH_SELECTOR_COLUMN (cell_layout);
1051
1052   view_column = gtk_tree_view_get_column (sel_column->priv->tree_view, 0);
1053
1054   gtk_cell_layout_clear (GTK_CELL_LAYOUT(view_column));
1055 }
1056
1057 static void
1058 hildon_touch_selector_column_cell_layout_add_attribute (GtkCellLayout         *cell_layout,
1059                                                   GtkCellRenderer       *cell,
1060                                                   const gchar           *attribute,
1061                                                   gint                   column)
1062 {
1063   HildonTouchSelectorColumn *sel_column = NULL;
1064   GtkTreeViewColumn *view_column = NULL;
1065
1066   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (cell_layout));
1067   sel_column = HILDON_TOUCH_SELECTOR_COLUMN (cell_layout);
1068
1069   view_column = gtk_tree_view_get_column (sel_column->priv->tree_view, 0);
1070
1071   gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT(view_column), cell, attribute, column);
1072 }
1073
1074
1075 static void
1076 hildon_touch_selector_column_cell_layout_set_cell_data_func (GtkCellLayout         *cell_layout,
1077                                                        GtkCellRenderer       *cell,
1078                                                        GtkCellLayoutDataFunc  func,
1079                                                        gpointer               func_data,
1080                                                        GDestroyNotify         destroy)
1081 {
1082   HildonTouchSelectorColumn *sel_column = NULL;
1083   GtkTreeViewColumn *view_column = NULL;
1084
1085   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (cell_layout));
1086   sel_column = HILDON_TOUCH_SELECTOR_COLUMN (cell_layout);
1087
1088   view_column = gtk_tree_view_get_column (sel_column->priv->tree_view, 0);
1089
1090   gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT(view_column), cell, func,
1091                                       func_data, destroy);
1092 }
1093
1094 static void
1095 hildon_touch_selector_column_cell_layout_clear_attributes (GtkCellLayout         *cell_layout,
1096                                                      GtkCellRenderer       *cell)
1097 {
1098   HildonTouchSelectorColumn *sel_column = NULL;
1099   GtkTreeViewColumn *view_column = NULL;
1100
1101   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (cell_layout));
1102   sel_column = HILDON_TOUCH_SELECTOR_COLUMN (cell_layout);
1103
1104   view_column = gtk_tree_view_get_column (sel_column->priv->tree_view, 0);
1105
1106   gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (view_column), cell);
1107 }
1108
1109 static void
1110 hildon_touch_selector_column_cell_layout_reorder (GtkCellLayout         *cell_layout,
1111                                             GtkCellRenderer       *cell,
1112                                             gint                   position)
1113 {
1114   HildonTouchSelectorColumn *sel_column = NULL;
1115   GtkTreeViewColumn *view_column = NULL;
1116
1117   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (cell_layout));
1118   sel_column = HILDON_TOUCH_SELECTOR_COLUMN (cell_layout);
1119
1120   view_column = gtk_tree_view_get_column (sel_column->priv->tree_view, 0);
1121
1122   gtk_cell_layout_reorder (GTK_CELL_LAYOUT(view_column), cell, position);
1123 }
1124
1125 static GList*
1126 hildon_touch_selector_column_cell_layout_get_cells (GtkCellLayout         *cell_layout)
1127 {
1128   HildonTouchSelectorColumn *sel_column = NULL;
1129   GtkTreeViewColumn *view_column = NULL;
1130
1131   g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (cell_layout), NULL);
1132   sel_column = HILDON_TOUCH_SELECTOR_COLUMN (cell_layout);
1133
1134   view_column = gtk_tree_view_get_column (sel_column->priv->tree_view, 0);
1135
1136   return gtk_cell_layout_get_cells (GTK_CELL_LAYOUT(view_column));
1137 }
1138
1139 /* ------------------------------ PUBLIC METHODS ---------------------------- */
1140
1141 /**
1142  * hildon_touch_selector_new:
1143  *
1144  * Creates a new empty #HildonTouchSelector.
1145  *
1146  * Returns: a new #HildonTouchSelector.
1147  *
1148  * Since: 2.2
1149  **/
1150 GtkWidget *
1151 hildon_touch_selector_new (void)
1152 {
1153   return g_object_new (HILDON_TYPE_TOUCH_SELECTOR, NULL);
1154 }
1155
1156 /**
1157  * hildon_touch_selector_new_text:
1158  *
1159  * Creates a #HildonTouchSelector with a single text column that
1160  * can be populated conveniently through hildon_touch_selector_append_text(),
1161  * hildon_touch_selector_prepend_text(), hildon_touch_selector_insert_text().
1162  *
1163  * Returns: A new #HildonTouchSelector
1164  *
1165  * Since: 2.2
1166  **/
1167 GtkWidget *
1168 hildon_touch_selector_new_text (void)
1169 {
1170   GtkWidget *selector;
1171   GtkListStore *store;
1172   HildonTouchSelectorColumn *column = NULL;
1173
1174   selector = hildon_touch_selector_new ();
1175   store = gtk_list_store_new (1, G_TYPE_STRING);
1176
1177   column = hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector),
1178                                                      GTK_TREE_MODEL (store), TRUE);
1179
1180   hildon_touch_selector_column_set_text_column (column, 0);
1181
1182   return selector;
1183 }
1184
1185 /**
1186  * hildon_touch_selector_append_text:
1187  * @selector: A #HildonTouchSelector.
1188  * @text: a non %NULL text string.
1189  *
1190  * Appends a new entry in a #HildonTouchSelector created with
1191  * hildon_touch_selector_new_text().
1192  *
1193  * Since: 2.2
1194  **/
1195 void
1196 hildon_touch_selector_append_text (HildonTouchSelector * selector,
1197                                    const gchar * text)
1198 {
1199   GtkTreeIter iter;
1200   GtkTreeModel *model;
1201
1202   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1203   g_return_if_fail (text != NULL);
1204
1205   model = hildon_touch_selector_get_model (HILDON_TOUCH_SELECTOR (selector), 0);
1206
1207   g_return_if_fail (GTK_IS_LIST_STORE (model));
1208
1209   gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1210   gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, text, -1);
1211 }
1212
1213 /**
1214  * hildon_touch_selector_prepend_text:
1215  * @selector: A #HildonTouchSelector.
1216  * @text: a non %NULL text string.
1217  *
1218  * Prepends a new entry in a #HildonTouchSelector created with
1219  * hildon_touch_selector_new_text().
1220  *
1221  * Since: 2.2
1222  **/
1223 void
1224 hildon_touch_selector_prepend_text (HildonTouchSelector * selector,
1225                                     const gchar * text)
1226 {
1227   GtkTreeIter iter;
1228   GtkTreeModel *model;
1229
1230   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1231   g_return_if_fail (text != NULL);
1232
1233   model = hildon_touch_selector_get_model (HILDON_TOUCH_SELECTOR (selector), 0);
1234
1235   g_return_if_fail (GTK_IS_LIST_STORE (model));
1236
1237   gtk_list_store_prepend (GTK_LIST_STORE (model), &iter);
1238   gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, text, -1);
1239 }
1240
1241 /**
1242  * hildon_touch_selector_insert_text:
1243  * @selector: a #HildonTouchSelector.
1244  * @position: the position to insert @text.
1245  * @text: A non %NULL text string.
1246  *
1247  * Inserts a new entry in a particular position of a
1248  * #HildonTouchSelector created with hildon_touch_selector_new_text().
1249  *
1250  * Since: 2.2
1251  **/
1252 void
1253 hildon_touch_selector_insert_text (HildonTouchSelector * selector,
1254                                    gint position, const gchar * text)
1255 {
1256   GtkTreeIter iter;
1257   GtkTreeModel *model;
1258
1259   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1260   g_return_if_fail (text != NULL);
1261   g_return_if_fail (position >= 0);
1262
1263   model = hildon_touch_selector_get_model (HILDON_TOUCH_SELECTOR (selector), 0);
1264
1265   g_return_if_fail (GTK_IS_LIST_STORE (model));
1266
1267   gtk_list_store_insert (GTK_LIST_STORE (model), &iter, position);
1268   gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, text, -1);
1269 }
1270
1271 /**
1272  * hildon_touch_selector_append_column
1273  * @selector: a #HildonTouchSelector
1274  * @model: the #GtkTreeModel with the data of the column
1275  * @cell_renderer: The #GtkCellRenderer where to draw each row contents.
1276  * @Varargs: a %NULL-terminated pair of attributes and column numbers.
1277  *
1278  * This functions adds a new column to the widget, whose data will
1279  * be obtained from the model. Only widgets added this way should used on
1280  * the selection logic, the print function, the #HildonTouchSelector::changed
1281  * signal, etc. Internally, a #GtkTreeView will be added to the widget, using
1282  * @model as the data source.
1283  *
1284  * You can optionally pass a #GtkCellRenderer in @cell_renderer,
1285  * together with a %NULL-terminated list of pairs property/value, in
1286  * the same way you would use gtk_tree_view_column_set_attributes().
1287  * This will pack @cell_renderer at the start of the column, expanded
1288  * by default.  If you prefer not to add it this way, you can simply
1289  * pass %NULL to @cell_renderer and use the #GtkCellLayout interface
1290  * on the returned #HildonTouchSelectorColumn to set your
1291  * renderers. Please note that the returned #HildonTouchSelectorColumn
1292  * is owned by @selector, you shouldn't unref it after setting it
1293  * up.
1294  *
1295  * Initially, the returned #HildonTouchSelectorColumn will have its
1296  * #HildonTouchSelectorColumn:text-column property unset. You should set
1297  * it to a column in @model with type %G_TYPE_STRING. See
1298  * hildon_touch_selector_column_set_text_column().
1299  *
1300  * This method could change the current #HildonTouchSelector:hildon-ui-mode.
1301  * %HILDON_UI_MODE_NORMAL is only allowed with one column, so if the selector
1302  * is in this mode, and a additional column is added,
1303  * #HildonTouchSelector:hildon-ui-mode will change to %HILDON_UI_MODE_EDIT.
1304  *
1305  * Returns: the new column added added, %NULL otherwise.
1306  *
1307  * Since: 2.2
1308  **/
1309
1310 HildonTouchSelectorColumn*
1311 hildon_touch_selector_append_column (HildonTouchSelector * selector,
1312                                      GtkTreeModel * model,
1313                                      GtkCellRenderer * cell_renderer, ...)
1314 {
1315   va_list args;
1316   HildonTouchSelectorColumn *new_column = NULL;
1317   gboolean emit_changed = FALSE;
1318   gint colnum;
1319
1320   g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), NULL);
1321   g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
1322
1323   if (model != NULL) {
1324
1325     va_start (args, cell_renderer);
1326     new_column = _create_new_column (selector, model, &emit_changed, cell_renderer, args);
1327     va_end (args);
1328
1329     selector->priv->columns = g_slist_append (selector->priv->columns,
1330                                               new_column);
1331     gtk_box_pack_start (GTK_BOX (selector->priv->hbox),
1332                         new_column->priv->panarea,
1333                         TRUE, TRUE, 6);
1334
1335     gtk_widget_show_all (new_column->priv->panarea);
1336
1337     if (selector->priv->initial_scroll) {
1338       _hildon_touch_selector_center_on_selected_items (selector, new_column);
1339     }
1340
1341   } else {
1342     return NULL;
1343   }
1344
1345   g_signal_emit (selector, hildon_touch_selector_signals[COLUMNS_CHANGED], 0);
1346   if (emit_changed) {
1347     colnum = g_slist_length (selector->priv->columns);
1348     hildon_touch_selector_emit_value_changed (selector, colnum);
1349   }
1350
1351   hildon_touch_selector_check_ui_mode_coherence (selector);
1352
1353   return new_column;
1354 }
1355
1356 /**
1357  * hildon_touch_selector_append_text_column
1358  * @selector: a #HildonTouchSelector
1359  * @model: a #GtkTreeModel with data for the column
1360  * @center: whether to center the text on the column
1361  *
1362  * Equivalent to hildon_touch_selector_append_column(), but using a
1363  * default text cell renderer. This is the most common use case of the
1364  * widget.
1365  *
1366  * Returns: the new column added, NULL otherwise.
1367  *
1368  * Since: 2.2
1369  **/
1370 HildonTouchSelectorColumn*
1371 hildon_touch_selector_append_text_column (HildonTouchSelector * selector,
1372                                           GtkTreeModel * model, gboolean center)
1373 {
1374   gfloat xalign = center ? 0.5 : 0.0;
1375   GtkCellRenderer *renderer;
1376
1377   g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), NULL);
1378   g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
1379
1380   renderer = gtk_cell_renderer_text_new ();
1381
1382   g_object_set (renderer,
1383                 "width", 1,
1384                 "xalign", xalign,
1385                 NULL);
1386
1387   return hildon_touch_selector_append_column (selector, model, renderer,
1388                                               "text", 0, NULL);
1389 }
1390
1391 /**
1392  * hildon_touch_selector_remove_column:
1393  * @selector: a #HildonTouchSelector
1394  * @column: the position of the column to be removed
1395  *
1396  * Removes a column from @selector.
1397  *
1398  * Returns: %TRUE if the column was removed, %FALSE otherwise
1399  *
1400  * Since: 2.2
1401  **/
1402 gboolean
1403 hildon_touch_selector_remove_column (HildonTouchSelector * selector, gint column)
1404 {
1405   HildonTouchSelectorColumn *current_column = NULL;
1406   HildonTouchSelectorPrivate *priv;
1407
1408   g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), FALSE);
1409   g_return_val_if_fail (column <
1410                         hildon_touch_selector_get_num_columns (selector), FALSE);
1411
1412   priv = HILDON_TOUCH_SELECTOR_GET_PRIVATE (selector);
1413   current_column = g_slist_nth_data (priv->columns, column);
1414
1415   gtk_container_remove (GTK_CONTAINER (priv->hbox), current_column->priv->panarea);
1416   priv->columns = g_slist_remove (priv->columns, current_column);
1417   g_object_unref (current_column);
1418
1419   g_signal_emit (selector, hildon_touch_selector_signals[COLUMNS_CHANGED], 0);
1420
1421   return TRUE;
1422 }
1423
1424 /**
1425  * hildon_touch_selector_set_column_attributes:
1426  * @selector: a #HildonTouchSelector
1427  * @num_column: the number of the column whose attributes we're setting
1428  * @cell_renderer: the #GtkCellRendere we're setting the attributes of
1429  * @Varargs: A %NULL-terminated list of attributes.
1430  *
1431  * Sets the attributes for the given column. The attributes must be given
1432  * in attribute/column pairs, just like in gtk_tree_view_column_set_attributes().
1433  * All existing attributes are removed and replaced with the new ones.
1434  *
1435  * Deprecated: #HildonTouchSelectorColumn implements #GtkCellLayout, use this
1436  *             interface instead. See
1437  *             hildon_touch_selector_get_column().
1438  *
1439  * Since: 2.2
1440  **/
1441 void
1442 hildon_touch_selector_set_column_attributes (HildonTouchSelector * selector,
1443                                              gint num_column,
1444                                              GtkCellRenderer * cell_renderer,
1445                                              ...)
1446 {
1447   va_list args;
1448   GtkTreeViewColumn *tree_column = NULL;
1449   HildonTouchSelectorColumn *current_column = NULL;
1450   gchar *attribute = NULL;
1451   gint value = 0;
1452
1453   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1454   g_return_if_fail (num_column <
1455                     hildon_touch_selector_get_num_columns (selector));
1456
1457   current_column = g_slist_nth_data (selector->priv->columns, num_column);
1458
1459   tree_column = gtk_tree_view_get_column (current_column->priv->tree_view, 0);
1460   gtk_tree_view_remove_column (current_column->priv->tree_view, tree_column);
1461
1462   tree_column = gtk_tree_view_column_new ();
1463   gtk_tree_view_column_pack_start (tree_column, cell_renderer, TRUE);
1464
1465   va_start (args, cell_renderer);
1466   attribute = va_arg (args, gchar *);
1467
1468   gtk_tree_view_column_clear_attributes (tree_column, cell_renderer);
1469
1470   while (attribute != NULL) {
1471     value = va_arg (args, gint);
1472     gtk_tree_view_column_add_attribute (tree_column, cell_renderer,
1473                                         attribute, value);
1474     attribute = va_arg (args, gchar *);
1475   }
1476
1477   va_end (args);
1478
1479   gtk_tree_view_append_column (current_column->priv->tree_view, tree_column);
1480 }
1481
1482 /**
1483  * hildon_touch_selector_get_num_columns:
1484  * @selector: a #HildonTouchSelector
1485  *
1486  * Gets the number of columns in the #HildonTouchSelector.
1487  *
1488  * Returns: the number of columns in @selector.
1489  *
1490  * Since: 2.2
1491  **/
1492 gint
1493 hildon_touch_selector_get_num_columns (HildonTouchSelector * selector)
1494 {
1495   g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), -1);
1496
1497   return g_slist_length (selector->priv->columns);
1498 }
1499
1500 /**
1501  * hildon_touch_selector_get_column_selection_mode:
1502  * @selector: a #HildonTouchSelector
1503  *
1504  * Gets the selection mode of @selector.
1505  *
1506  * Returns: one of #HildonTouchSelectorSelectionMode
1507  *
1508  * Since: 2.2
1509  **/
1510 HildonTouchSelectorSelectionMode
1511 hildon_touch_selector_get_column_selection_mode (HildonTouchSelector * selector)
1512 {
1513   HildonTouchSelectorSelectionMode result =
1514     HILDON_TOUCH_SELECTOR_SELECTION_MODE_SINGLE;
1515   GtkSelectionMode treeview_mode = GTK_SELECTION_BROWSE;
1516   HildonTouchSelectorColumn *column = NULL;
1517   GtkTreeSelection *selection = NULL;
1518
1519   g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), result);
1520   g_return_val_if_fail (hildon_touch_selector_get_num_columns (selector) > 0,
1521                         result);
1522
1523   column = HILDON_TOUCH_SELECTOR_COLUMN (selector->priv->columns->data);
1524
1525   selection = gtk_tree_view_get_selection (column->priv->tree_view);
1526   treeview_mode = gtk_tree_selection_get_mode (selection);
1527
1528
1529   if (treeview_mode == GTK_SELECTION_MULTIPLE) {
1530     result = HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE;
1531   } else {
1532     result = HILDON_TOUCH_SELECTOR_SELECTION_MODE_SINGLE;
1533   }
1534
1535   return result;
1536 }
1537
1538 /**
1539  * hildon_touch_selector_set_column_selection_mode:
1540  * @selector: a #HildonTouchSelector
1541  * @mode: the #HildonTouchSelectorMode for @selector
1542  *
1543  * Sets the selection mode for @selector. See #HildonTouchSelectorSelectionMode.
1544  *
1545  * The new @mode will be set, but take into into account that the
1546  * #HildonTouchSelectorSelectionMode is ignored if the @selector
1547  * #HildonTouchSelector:hildon-ui-mode property is set to %HILDON_UI_MODE_NORMAL
1548  *
1549  * Since: 2.2
1550  **/
1551 void
1552 hildon_touch_selector_set_column_selection_mode (HildonTouchSelector * selector,
1553                                                  HildonTouchSelectorSelectionMode mode)
1554 {
1555   GtkTreeView *tv = NULL;
1556   HildonTouchSelectorColumn *column = NULL;
1557   GtkTreeSelection *selection = NULL;
1558   GtkSelectionMode treeview_mode = GTK_SELECTION_MULTIPLE;
1559   GtkTreeIter iter;
1560   HildonTouchSelectorSelectionMode current_mode;
1561
1562   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1563   g_return_if_fail (hildon_touch_selector_get_num_columns (selector) > 0);
1564
1565   current_mode = hildon_touch_selector_get_column_selection_mode (selector);
1566
1567   if (current_mode == mode) {
1568     return;
1569   }
1570
1571   column = HILDON_TOUCH_SELECTOR_COLUMN ((g_slist_nth (selector->priv->columns, 0))->data);
1572   tv = column->priv->tree_view;
1573
1574   if (tv) {
1575     switch (mode) {
1576     case HILDON_TOUCH_SELECTOR_SELECTION_MODE_SINGLE:
1577       treeview_mode = GTK_SELECTION_BROWSE;
1578       break;
1579     case HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE:
1580       treeview_mode = GTK_SELECTION_MULTIPLE;
1581       break;
1582     }
1583
1584     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
1585     gtk_tree_selection_set_mode (selection, treeview_mode);
1586
1587     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
1588     gtk_tree_model_get_iter_first (column->priv->model, &iter);
1589     gtk_tree_selection_unselect_all (selection);
1590     gtk_tree_selection_select_iter (selection, &iter);
1591
1592     /* the column changed was the first one */
1593     hildon_touch_selector_emit_value_changed (selector, 0);
1594   }
1595
1596 }
1597
1598 /**
1599  * hildon_touch_selector_set_print_func:
1600  * @selector: a #HildonTouchSelector
1601  * @func: a #HildonTouchSelectorPrintFunc function
1602  *
1603  * Sets the function to be used by hildon_touch_selector_get_current_text().
1604  * See hildon_touch_selector_set_print_func_full().
1605  *
1606  * Since: 2.2
1607  **/
1608 void
1609 hildon_touch_selector_set_print_func (HildonTouchSelector * selector,
1610                                       HildonTouchSelectorPrintFunc func)
1611 {
1612   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1613
1614   hildon_touch_selector_set_print_func_full (selector, func, NULL, NULL);
1615 }
1616
1617 /**
1618  * hildon_touch_selector_set_print_func_full:
1619  * @selector: a #HildonTouchSelector
1620  * @func: a #HildonTouchSelectorPrintFunc function
1621  * @user_data: a pointer to user data or %NULL
1622  * @destroy_func: a callback for freeing the user data or %NULL
1623  *
1624  * Sets the function to be used by hildon_touch_selector_get_current_text()
1625  * to produce a text representation of the currently selected items in @selector.
1626  * The default function will return a concatenation of comma separated items
1627  * selected in each column in @selector. Use this to override this method if you
1628  * need a particular representation for your application.
1629  *
1630  * Since: 2.2
1631  **/
1632 void
1633 hildon_touch_selector_set_print_func_full (HildonTouchSelector          *selector,
1634                                            HildonTouchSelectorPrintFunc  func,
1635                                            gpointer                      user_data,
1636                                            GDestroyNotify                destroy_func)
1637 {
1638   gpointer       old_user_data;
1639   GDestroyNotify old_destroy_func;
1640
1641   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1642
1643   old_user_data = selector->priv->print_user_data;
1644   old_destroy_func = selector->priv->print_destroy_func;
1645
1646   selector->priv->print_func = func;
1647   selector->priv->print_user_data = user_data;
1648   selector->priv->print_destroy_func = destroy_func;
1649
1650   if (old_destroy_func && old_user_data != user_data)
1651     (*old_destroy_func) (old_user_data);
1652 }
1653
1654 /**
1655  * hildon_touch_selector_get_print_func:
1656  * @selector: a #HildonTouchSelector
1657  *
1658  * Gets the #HildonTouchSelectorPrintFunc currently used. See
1659  * hildon_touch_selector_set_print_func().
1660  *
1661  * Returns: a #HildonTouchSelectorPrintFunc or %NULL if the default
1662  * one is currently used.
1663  **/
1664 HildonTouchSelectorPrintFunc
1665 hildon_touch_selector_get_print_func (HildonTouchSelector * selector)
1666 {
1667   g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), NULL);
1668
1669   return selector->priv->print_func;
1670 }
1671
1672 /**
1673  * hildon_touch_selector_set_active:
1674  * @selector: a #HildonTouchSelector
1675  * @column: column number
1676  * @index: the index of the item to select, or -1 to have no active item
1677  *
1678  * Sets the active item of the #HildonTouchSelector to @index. The
1679  * column number is taken from @column.
1680  *
1681  * @selector must be in %HILDON_TOUCH_SELECTOR_SELECTION_MODE_SINGLE
1682  *
1683  * Since: 2.2
1684  **/
1685 void
1686 hildon_touch_selector_set_active                (HildonTouchSelector *selector,
1687                                                  gint                 column,
1688                                                  gint                 index)
1689 {
1690   GtkTreeSelection *selection = NULL;
1691   HildonTouchSelectorColumn *current_column = NULL;
1692   HildonTouchSelectorSelectionMode mode;
1693   GtkTreePath *path;
1694
1695   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1696   g_return_if_fail (column < hildon_touch_selector_get_num_columns (selector));
1697   mode = hildon_touch_selector_get_column_selection_mode (selector);
1698   g_return_if_fail (mode == HILDON_TOUCH_SELECTOR_SELECTION_MODE_SINGLE);
1699
1700   current_column = g_slist_nth_data (selector->priv->columns, column);
1701
1702   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (current_column->priv->tree_view));
1703   path = gtk_tree_path_new_from_indices (index, -1);
1704   gtk_tree_selection_unselect_all (selection);
1705   if (index != -1)
1706     gtk_tree_selection_select_path (selection, path);
1707
1708   hildon_touch_selector_emit_value_changed (selector, column);
1709
1710   gtk_tree_path_free (path);
1711 }
1712
1713 /**
1714  * hildon_touch_selector_get_active:
1715  * @selector: a #HildonTouchSelector
1716  * @column: column number
1717  *
1718  * Returns the index of the currently active item in column number
1719  * @column, or -1 if there's no active item.
1720  *
1721  * @selector must be in %HILDON_TOUCH_SELECTOR_SELECTION_MODE_SINGLE
1722  *
1723  * Returns: an integer which is the index of the currently active
1724  * item, or -1 if there's no active item.
1725  *
1726  * Since: 2.2
1727  **/
1728 gint
1729 hildon_touch_selector_get_active                (HildonTouchSelector *selector,
1730                                                  gint                 column)
1731 {
1732   GtkTreeSelection *selection = NULL;
1733   HildonTouchSelectorColumn *current_column = NULL;
1734   HildonTouchSelectorSelectionMode mode;
1735   GtkTreeModel *model;
1736   GtkTreeIter iter;
1737   GtkTreePath *path;
1738   gint index;
1739
1740   g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), -1);
1741   g_return_val_if_fail (column < hildon_touch_selector_get_num_columns (selector), -1);
1742   mode = hildon_touch_selector_get_column_selection_mode (selector);
1743   g_return_val_if_fail (mode == HILDON_TOUCH_SELECTOR_SELECTION_MODE_SINGLE, -1);
1744
1745   current_column = g_slist_nth_data (selector->priv->columns, column);
1746
1747   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (current_column->priv->tree_view));
1748   g_return_val_if_fail (gtk_tree_selection_get_selected (selection, NULL, &iter), -1);
1749
1750   model = gtk_tree_view_get_model (GTK_TREE_VIEW (current_column->priv->tree_view));
1751   path = gtk_tree_model_get_path (model, &iter);
1752   index = (gtk_tree_path_get_indices (path))[0];
1753
1754   gtk_tree_path_free (path);
1755
1756   return index;
1757 }
1758
1759 /**
1760  * hildon_touch_selector_get_selected:
1761  * @selector: a #HildonTouchSelector
1762  * @column: the column number we want to get the element
1763  * @iter: #GtkTreeIter currently selected
1764  *
1765  * Sets @iter to the currently selected node on the nth-column, if selection is
1766  * set to %HILDON_TOUCH_SELECTOR_SINGLE or %HILDON_TOUCH_SELECTOR_MULTIPLE with
1767  * a column different that the first one. @iter may be %NULL if you just want to
1768  * test if selection has any selected items.
1769  *
1770  * This function will not work if selection is in
1771  * %HILDON_TOUCH_SELECTOR_MULTIPLE mode and the column is the first one.
1772  *
1773  * See gtk_tree_selection_get_selected() for more information.
1774  *
1775  * Returns: %TRUE if @iter was correctly set, %FALSE otherwise
1776  *
1777  * Since: 2.2
1778  **/
1779 gboolean
1780 hildon_touch_selector_get_selected (HildonTouchSelector * selector,
1781                                     gint column, GtkTreeIter * iter)
1782 {
1783   GtkTreeSelection *selection = NULL;
1784   HildonTouchSelectorColumn *current_column = NULL;
1785   HildonTouchSelectorSelectionMode mode;
1786
1787   g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), FALSE);
1788   g_return_val_if_fail (column < hildon_touch_selector_get_num_columns (selector),
1789                         FALSE);
1790   mode = hildon_touch_selector_get_column_selection_mode (selector);
1791   g_return_val_if_fail
1792     ((mode == HILDON_TOUCH_SELECTOR_SELECTION_MODE_SINGLE) ||
1793      ((mode == HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE)&&(column>0)),
1794      FALSE);
1795
1796   current_column = g_slist_nth_data (selector->priv->columns, column);
1797
1798   selection =
1799     gtk_tree_view_get_selection (GTK_TREE_VIEW (current_column->priv->tree_view));
1800
1801   return gtk_tree_selection_get_selected (selection, NULL, iter);
1802 }
1803
1804 /**
1805  * hildon_touch_selector_select_iter
1806  * @selector: a #HildonTouchSelector
1807  * @column:   the column to selects
1808  * @iter:     the #GtkTreeIter to be selected
1809  * @scroll_to: whether to smoothly scroll to the item
1810  *
1811  * Sets the currently selected item in the column @column to the one pointed by @iter,
1812  * optionally smoothly scrolling to it.
1813  *
1814  * Since: 2.2
1815  **/
1816 void
1817 hildon_touch_selector_select_iter (HildonTouchSelector * selector,
1818                                    gint column, GtkTreeIter * iter,
1819                                    gboolean scroll_to)
1820 {
1821   GtkTreePath *path;
1822   GtkTreeModel *model;
1823   HildonTouchSelectorColumn *current_column = NULL;
1824   GtkTreeView *tv = NULL;
1825   GtkTreeSelection *selection = NULL;
1826
1827   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1828   g_return_if_fail (column < hildon_touch_selector_get_num_columns (selector));
1829
1830   current_column = g_slist_nth_data (selector->priv->columns, column);
1831
1832   tv = current_column->priv->tree_view;
1833   selection = gtk_tree_view_get_selection (tv);
1834   model = gtk_tree_view_get_model (tv);
1835   path = gtk_tree_model_get_path (model, iter);
1836
1837   gtk_tree_selection_select_iter (selection, iter);
1838
1839   if (scroll_to) {
1840     hildon_touch_selector_scroll_to (current_column, tv, path);
1841   }
1842
1843   hildon_touch_selector_emit_value_changed (selector, column);
1844
1845   gtk_tree_path_free (path);
1846 }
1847
1848 /**
1849  * hildon_touch_selector_unselect_iter
1850  * @selector: a #HildonTouchSelector
1851  * @column:   the column to unselects from
1852  * @iter:     the #GtkTreeIter to be unselected
1853  *
1854  * Unselect the item pointed by @iter in the column @column
1855  *
1856  * Since: 2.2
1857  **/
1858
1859 void hildon_touch_selector_unselect_iter (HildonTouchSelector * selector,
1860                                           gint column,
1861                                           GtkTreeIter * iter)
1862 {
1863   HildonTouchSelectorColumn *current_column = NULL;
1864   GtkTreeSelection *selection = NULL;
1865
1866   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1867   g_return_if_fail (column < hildon_touch_selector_get_num_columns (selector));
1868
1869   current_column = g_slist_nth_data (selector->priv->columns, column);
1870   selection = gtk_tree_view_get_selection (current_column->priv->tree_view);
1871   gtk_tree_selection_unselect_iter (selection, iter);
1872
1873   hildon_touch_selector_emit_value_changed (selector, column);
1874 }
1875
1876 /**
1877  * hildon_touch_selector_unselect_all:
1878  * @selector: a #HildonTouchSelector
1879  * @column: the position of the column to get the selected rows from
1880  *
1881  * Unselects all the selected items in the column @column.
1882  *
1883  * Since: 2.2
1884  **/
1885 void
1886 hildon_touch_selector_unselect_all (HildonTouchSelector * selector,
1887                                     gint column)
1888 {
1889   HildonTouchSelectorColumn *current_column = NULL;
1890   GtkTreeSelection *selection = NULL;
1891
1892   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1893   g_return_if_fail (column < hildon_touch_selector_get_num_columns (selector));
1894
1895   current_column = g_slist_nth_data (selector->priv->columns, column);
1896   selection = gtk_tree_view_get_selection (current_column->priv->tree_view);
1897   gtk_tree_selection_unselect_all (selection);
1898
1899   hildon_touch_selector_emit_value_changed (selector, column);
1900 }
1901
1902 /**
1903  * hildon_touch_selector_get_selected_rows:
1904  * @selector: a #HildonTouchSelector
1905  * @column: the position of the column to get the selected rows from
1906  *
1907  * Creates a list of #GtkTreePath<!-- -->s of all selected rows in a column. Additionally,
1908  * if you to plan to modify the model after calling this function, you may
1909  * want to convert the returned list into a list of GtkTreeRowReferences. To do this,
1910  * you can use gtk_tree_row_reference_new().
1911  *
1912  * See gtk_tree_selection_get_selected_rows() for more information.
1913  *
1914  * Returns: A new #GList containing a #GtkTreePath for each selected row in the column @column.
1915  *
1916  * Since: 2.2
1917  **/
1918 GList *
1919 hildon_touch_selector_get_selected_rows (HildonTouchSelector * selector,
1920                                          gint column)
1921 {
1922   GList *result = NULL;
1923   HildonTouchSelectorColumn *current_column = NULL;
1924   GtkTreeSelection *selection = NULL;
1925
1926   g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), NULL);
1927   g_return_val_if_fail (column < hildon_touch_selector_get_num_columns (selector),
1928                         NULL);
1929
1930   current_column = g_slist_nth_data (selector->priv->columns, column);
1931   selection = gtk_tree_view_get_selection (current_column->priv->tree_view);
1932
1933   result = gtk_tree_selection_get_selected_rows (selection, NULL);
1934
1935   return result;
1936 }
1937
1938 /**
1939  * hildon_touch_selector_get_model:
1940  * @selector: a #HildonTouchSelector
1941  * @column: the position of the column in @selector
1942  *
1943  * Gets the model of a column of @selector.
1944  *
1945  * Returns: the #GtkTreeModel for the column @column of @selector.
1946  *
1947  * Since: 2.2
1948  **/
1949 GtkTreeModel *
1950 hildon_touch_selector_get_model (HildonTouchSelector * selector, gint column)
1951 {
1952   HildonTouchSelectorColumn *current_column = NULL;
1953
1954   g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), NULL);
1955   g_return_val_if_fail (column < hildon_touch_selector_get_num_columns (selector),
1956                         NULL);
1957
1958   current_column = g_slist_nth_data (selector->priv->columns, column);
1959
1960   return current_column->priv->model;
1961 }
1962
1963 static void
1964 on_row_changed (GtkTreeModel *model,
1965                 GtkTreePath *path,
1966                 GtkTreeIter *iter,
1967                 gpointer userdata)
1968 {
1969   HildonTouchSelector *selector;
1970   HildonTouchSelectorColumn *current_column;
1971
1972   gint column = 0;
1973   GSList *col;
1974
1975   selector = HILDON_TOUCH_SELECTOR (userdata);
1976
1977   for (col = selector->priv->columns; col != NULL; col = col->next) {
1978     current_column = HILDON_TOUCH_SELECTOR_COLUMN (col->data);
1979     if (current_column->priv->model == model &&
1980         gtk_tree_selection_path_is_selected (gtk_tree_view_get_selection (current_column->priv->tree_view),
1981                                              path)) {
1982       hildon_touch_selector_emit_value_changed (selector, column);
1983     }
1984     column ++;
1985   }
1986 }
1987
1988 static void
1989 _hildon_touch_selector_set_model (HildonTouchSelector * selector,
1990                                   gint column, GtkTreeModel * model)
1991 {
1992   HildonTouchSelectorColumn *current_column = NULL;
1993
1994   current_column =
1995     HILDON_TOUCH_SELECTOR_COLUMN (g_slist_nth_data (selector->priv->columns, column));
1996
1997   if (current_column->priv->model) {
1998     g_signal_handlers_disconnect_by_func (current_column->priv->model,
1999                                           on_row_changed, selector);
2000   }
2001   current_column->priv->model = model;
2002   gtk_tree_view_set_model (current_column->priv->tree_view,
2003                            current_column->priv->model);
2004   g_signal_connect (model, "row-changed",
2005                     G_CALLBACK (on_row_changed), selector);
2006 }
2007
2008 /**
2009  * hildon_touch_selector_set_model:
2010  * @selector: a #HildonTouchSelector
2011  * @column: the position of the column to set the model to
2012  * @model: a #GtkTreeModel
2013  *
2014  * Sets the #GtkTreeModel for a particular column in @model.
2015  *
2016  * Since: 2.2
2017  **/
2018 void
2019 hildon_touch_selector_set_model (HildonTouchSelector * selector,
2020                                  gint column, GtkTreeModel * model)
2021 {
2022   g_return_if_fail (HILDON_TOUCH_SELECTOR (selector));
2023   g_return_if_fail (column < hildon_touch_selector_get_num_columns (selector));
2024
2025   HILDON_TOUCH_SELECTOR_GET_CLASS (selector)->set_model (selector, column, model);
2026 }
2027
2028 /**
2029  * hildon_touch_selector_get_current_text:
2030  * @selector: a #HildonTouchSelector
2031  *
2032  * Returns a string representing the currently selected items for
2033  * each column of @selector. See hildon_touch_selector_set_print_func().
2034  *
2035  * Returns: a newly allocated string.
2036  *
2037  * Since: 2.2
2038  **/
2039 gchar *
2040 hildon_touch_selector_get_current_text (HildonTouchSelector * selector)
2041 {
2042   gchar *result = NULL;
2043   g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), NULL);
2044
2045   if (selector->priv->print_func) {
2046     result = (*selector->priv->print_func) (selector, selector->priv->print_user_data);
2047   } else {
2048     result = _default_print_func (selector, NULL);
2049   }
2050
2051   return result;
2052 }
2053
2054 static void
2055 search_nearest_element (HildonPannableArea *panarea,
2056                         GtkTreeView *tv,
2057                         GList *selected_rows,
2058                         GtkTreePath **nearest_path)
2059 {
2060   GtkAdjustment *adj = NULL;
2061   gdouble target_value = 0;
2062   GdkRectangle rect;
2063   GList *iter = NULL;
2064   GtkTreePath *path = NULL;
2065   gint y = -1;
2066   gdouble nearest_distance = -1;
2067   gdouble current_distance = -1;
2068   GtkTreePath *result_path = NULL;
2069
2070   g_assert (nearest_path != NULL);
2071
2072   if (selected_rows == NULL) {
2073     *nearest_path = NULL;
2074     return;
2075   }
2076
2077   adj = hildon_pannable_area_get_vadjustment (panarea);
2078   g_return_if_fail (adj != NULL);
2079
2080   /* we add this in order to check the nearest to the center of
2081      the visible area */
2082   target_value = gtk_adjustment_get_value (adj) + adj->page_size/2;
2083
2084   path = result_path = selected_rows->data;
2085   gtk_tree_view_get_background_area (tv, path, NULL, &rect);
2086   gtk_tree_view_convert_bin_window_to_tree_coords (tv, 0, rect.y, NULL, &y);
2087   nearest_distance = abs (target_value - y);
2088
2089   for (iter = selected_rows->next; iter; iter = g_list_next (iter)) {
2090     gtk_tree_view_get_background_area (tv, path, NULL, &rect);
2091     gtk_tree_view_convert_bin_window_to_tree_coords (tv, 0, rect.y, NULL, &y);
2092     current_distance = abs (target_value - y);
2093     if (current_distance < nearest_distance) {
2094       nearest_distance = current_distance;
2095       result_path = path;
2096     }
2097   }
2098
2099   *nearest_path = result_path;
2100 }
2101
2102 static gboolean
2103 on_realize_cb                                  (GtkWidget *widget,
2104                                                 gpointer data)
2105 {
2106   HildonTouchSelectorColumn *column = NULL;
2107   GdkRectangle rect;
2108   gint y;
2109
2110   column = HILDON_TOUCH_SELECTOR_COLUMN (data);
2111
2112   if (column->priv->initial_path) {
2113     gtk_tree_view_get_background_area (GTK_TREE_VIEW (column->priv->tree_view),
2114                                        column->priv->initial_path, NULL, &rect);
2115     gtk_tree_view_convert_bin_window_to_tree_coords
2116       (GTK_TREE_VIEW (column->priv->tree_view),
2117        0, rect.y, NULL, &y);
2118
2119     hildon_pannable_area_scroll_to (HILDON_PANNABLE_AREA (column->priv->panarea),
2120                                     -1, y);
2121
2122     gtk_tree_path_free (column->priv->initial_path);
2123
2124     column->priv->initial_path = NULL;
2125
2126   }
2127
2128   g_signal_handler_disconnect (column->priv->panarea,
2129                                column->priv->realize_handler);
2130
2131   return FALSE;
2132 }
2133
2134 static void
2135 hildon_touch_selector_scroll_to (HildonTouchSelectorColumn *column,
2136                                  GtkTreeView *tv,
2137                                  GtkTreePath *path)
2138 {
2139   if (GTK_WIDGET_REALIZED (column->priv->panarea)) {
2140     GdkRectangle rect;
2141     gint y;
2142
2143     gtk_tree_view_get_background_area (tv,
2144                                        path, NULL, &rect);
2145     gtk_tree_view_convert_bin_window_to_tree_coords (tv,
2146                                                      0, rect.y, NULL, &y);
2147
2148     hildon_pannable_area_scroll_to (HILDON_PANNABLE_AREA
2149                                     (column->priv->panarea), -1, y);
2150   } else {
2151     if (column->priv->realize_handler != 0) {
2152
2153       if (column->priv->initial_path) {
2154         gtk_tree_path_free (column->priv->initial_path);
2155         column->priv->initial_path = NULL;
2156       }
2157
2158       g_signal_handler_disconnect (column->priv->panarea,
2159                                    column->priv->realize_handler);
2160       column->priv->realize_handler = 0;
2161     }
2162
2163     column->priv->initial_path = gtk_tree_path_copy (path);
2164     column->priv->realize_handler =
2165       g_signal_connect_after (G_OBJECT (column->priv->panarea), "realize",
2166                               G_CALLBACK (on_realize_cb),
2167                               column);
2168   }
2169 }
2170
2171 /**
2172  *
2173  * Center on the selected item of a concrete column
2174  *
2175  * Returns: TRUE if was able to do that
2176  *          FALSE otherwise
2177  */
2178 static gboolean
2179 _hildon_touch_selector_center_on_selected_items (HildonTouchSelector *selector,
2180                                                  HildonTouchSelectorColumn *column)
2181 {
2182   GtkTreePath *path = NULL;
2183   GList *selected_rows = NULL;
2184   gint num_column = -1;
2185
2186   num_column = g_slist_index (selector->priv->columns, column);
2187
2188   selected_rows = hildon_touch_selector_get_selected_rows (selector, num_column);
2189   if (selected_rows) {
2190     search_nearest_element (HILDON_PANNABLE_AREA (column->priv->panarea),
2191                              GTK_TREE_VIEW (column->priv->tree_view),
2192                              selected_rows,
2193                              &path);
2194
2195     if (path != NULL) {
2196       hildon_touch_selector_scroll_to (column,
2197                                        GTK_TREE_VIEW (column->priv->tree_view),
2198                                        path);
2199     } else {
2200       return FALSE;
2201     }
2202
2203     g_list_foreach (selected_rows, (GFunc) (gtk_tree_path_free), NULL);
2204     g_list_free (selected_rows);
2205   }
2206
2207   return TRUE;
2208 }
2209
2210 static gboolean
2211 _hildon_touch_selector_has_multiple_selection (HildonTouchSelector * selector)
2212 {
2213   HildonTouchSelectorSelectionMode mode;
2214   gint n_columns;
2215
2216   n_columns = hildon_touch_selector_get_num_columns (selector);
2217   mode = hildon_touch_selector_get_column_selection_mode (selector);
2218
2219   return ((n_columns > 1) || (mode == HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE));
2220 }
2221
2222 /**
2223  * hildon_touch_selector_has_multiple_selection:
2224  * @selector: A #HildonTouchSelector
2225  *
2226  * Determines whether @selector is complex enough to actually require an
2227  * extra selection step than only picking an item. This is normally %TRUE
2228  * if @selector has multiple columns, multiple selection, or when it is a
2229  * more complex widget, like #HildonTouchSelectorEntry.
2230  *
2231  * This information is useful for widgets containing a #HildonTouchSelector,
2232  * like #HildonPickerDialog, that could need a "Done" button, in case that
2233  * its internal #HildonTouchSelector has multiple columns, for instance.
2234  *
2235  * Returns: %TRUE if @selector requires multiple selection steps.
2236  *
2237  * Since: 2.2
2238  **/
2239 gboolean
2240 hildon_touch_selector_has_multiple_selection (HildonTouchSelector * selector)
2241 {
2242   g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), FALSE);
2243
2244   return HILDON_TOUCH_SELECTOR_GET_CLASS (selector)->has_multiple_selection (selector);
2245 }
2246
2247
2248 /**
2249  * hildon_touch_selector_get_column:
2250  * @selector: A #HildonTouchSelector
2251  * @column: a column number
2252  *
2253  * Use this method to retrieve a #HildonTouchSelectorColumn. Then, you can use
2254  * the #GtkCellLayout interface to set up the layout of the column.
2255  *
2256  * Returns: the @column<!-- -->-th #HildonTouchSelectorColumn in @selector
2257  *
2258  * Since: 2.2
2259  **/
2260 HildonTouchSelectorColumn *
2261 hildon_touch_selector_get_column (HildonTouchSelector * selector,
2262                                   gint column)
2263 {
2264   gint num_columns = -1;
2265
2266   g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), NULL);
2267   num_columns = hildon_touch_selector_get_num_columns (selector);
2268   g_return_val_if_fail (column < num_columns && column >= 0, NULL);
2269
2270   return g_slist_nth_data (selector->priv->columns, column);
2271 }
2272
2273
2274 /**
2275  * hildon_touch_selector_center_on_selected:
2276  * @selector: a #HildonTouchSelector
2277  *
2278  * Ensures all the columns in a #HildonTouchSelector show a selected
2279  * item. If one of the columns is in
2280  * %HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE mode, that column
2281  * will be scrolled to ensure the selected item that is closest to the
2282  * currently visible area is shown.
2283  *
2284  * The #HildonTouchSelector:initial-scroll property configure the widget
2285  * in order to use this function at the first show.
2286  *
2287  * Take into account that the element is not centered until the widget is
2288  * realized. If the widget is not realized when the function is called, it
2289  * will be postponed. If you call this functions several times before the
2290  * widgets is realized, only the last one will be used.
2291  *
2292  * This behaviour includes any call to hildon_touch_selector_center_on_index(),
2293  * so take care calling this functions, or with the
2294  * #HildonTouchSelector:initial-scroll property in order to get centered on the
2295  * proper element.
2296  *
2297  * Since: 2.2
2298  **/
2299 void
2300 hildon_touch_selector_center_on_selected         (HildonTouchSelector *selector)
2301 {
2302   GSList *iter = NULL;
2303
2304   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
2305
2306   for (iter = selector->priv->columns; iter; iter = g_slist_next (iter)) {
2307     _hildon_touch_selector_center_on_selected_items (selector,
2308                                                     HILDON_TOUCH_SELECTOR_COLUMN (iter->data));
2309   }
2310 }
2311
2312 /**
2313  * hildon_touch_selector_optimal_size_request
2314  * @selector: a #HildonTouchSelector
2315  * @requisition: a #GtkRequisition
2316  *
2317  * Gets the optimal size request of the touch selector. This function is mostly
2318  * intended for dialog implementations that include a #HildonTouchSelector and
2319  * want to optimize the screen real state, for example, when you want a dialog
2320  * to show as much of the selector, avoiding any extra empty space below the
2321  * selector.
2322  *
2323  * See #HildonPickerDialog implementation for an example.
2324  *
2325  * This function is oriented to be used in the size_request of a dialog or window,
2326  * if you are not sure do not use it.
2327  *
2328  * There is a precondition to this function: Since this function does not
2329  * call the "size_request" method, it can only be used when you know that
2330  * gtk_widget_size_request() has been called since the last time a resize was
2331  * queued.
2332  *
2333  * Since: 2.2
2334  **/
2335 void
2336 hildon_touch_selector_optimal_size_request      (HildonTouchSelector *selector,
2337                                                  GtkRequisition *requisition)
2338 {
2339   GSList *iter = NULL;
2340   gint height = 0;
2341   gint base_height = 0;
2342
2343   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
2344
2345   iter = selector->priv->columns;
2346
2347   /* Default optimal values are the current ones */
2348   gtk_widget_get_child_requisition (GTK_WIDGET (selector),
2349                                     requisition);
2350
2351   if (iter == NULL) {
2352     height = requisition->height;
2353   } else {
2354     /* we use the normal requisition as base, as the touch selector can has
2355        extra widgets, not only the columns (ie: HildonTouchSelectorEntry) */
2356     base_height = requisition->height;
2357   }
2358
2359   /* Compute optimal height for the columns */
2360   while (iter) {
2361     HildonTouchSelectorColumn *column;
2362     GtkWidget *child;
2363     GtkRequisition child_requisition = {0};
2364
2365     column = HILDON_TOUCH_SELECTOR_COLUMN (iter->data);
2366     child = GTK_WIDGET (column->priv->tree_view);
2367
2368     gtk_widget_get_child_requisition (child, &child_requisition);
2369
2370     height = MAX (height, child_requisition.height);
2371
2372     iter = g_slist_next (iter);
2373   }
2374
2375   requisition->height = base_height + height;
2376 }
2377
2378
2379
2380 /**
2381  * hildon_touch_selector_get_hildon_ui_mode
2382  * @selector: a #HildonTouchSelector
2383  *
2384  * Gets the current hildon-ui-mode, see #HildonUIMode for more information
2385  *
2386  * Returns: the current hildon-ui-mode
2387  *
2388  * Since: 2.2
2389  **/
2390 HildonUIMode
2391 hildon_touch_selector_get_hildon_ui_mode        (HildonTouchSelector *selector)
2392 {
2393   g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), HILDON_UI_MODE_EDIT);
2394
2395   return selector->priv->hildon_ui_mode;
2396 }
2397
2398 /**
2399  * hildon_touch_selector_set_hildon_ui_mode
2400  * @selector: a #HildonTouchSelector
2401  * @mode: a #HildonUIMode
2402  *
2403  * Sets the value of the property #HildonTouchSelector:hildon-ui-mode to be @mode,
2404  * see #HildonUIMode for more information
2405  *
2406  * Note that the %HILDON_UI_MODE_NORMAL can be only used when the selector has
2407  * one column, use the return value to check if the change was effective.
2408  *
2409  * Returns: %TRUE if #HildonTouchSelector:hildon-ui-mode was changed
2410  *          %FALSE otherwise
2411  *
2412  * Since: 2.2
2413  **/
2414 gboolean
2415 hildon_touch_selector_set_hildon_ui_mode        (HildonTouchSelector *selector,
2416                                                  HildonUIMode         mode)
2417 {
2418   gint num = 0;
2419   GSList *iter = NULL;
2420   HildonTouchSelectorColumn *column = NULL;
2421   GtkTreeView *tree_view = NULL;
2422
2423   g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), FALSE);
2424   num = hildon_touch_selector_get_num_columns (selector);
2425   g_return_val_if_fail ((mode == HILDON_UI_MODE_EDIT) || (num == 1), FALSE);
2426
2427   if (mode == selector->priv->hildon_ui_mode) {
2428     return FALSE;
2429   }
2430
2431   for (iter = selector->priv->columns; iter; iter = g_slist_next (iter)) {
2432     column = HILDON_TOUCH_SELECTOR_COLUMN (iter->data);
2433     tree_view = column->priv->tree_view;
2434
2435     hildon_tree_view_set_hildon_ui_mode (tree_view, mode);
2436
2437     /* looking at the code of hildon_tree_view_set_hildon_ui_mode, it seems
2438        that it call the unselect_all, but it is required anyway */
2439     if (mode == HILDON_UI_MODE_NORMAL) {
2440       GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
2441
2442       gtk_tree_selection_unselect_all (selection);
2443     }
2444   }
2445
2446   selector->priv->hildon_ui_mode = mode;
2447
2448   return TRUE;
2449 }
2450
2451 /**
2452  * hildon_touch_selector_get_last_activated_row
2453  * @selector: a #HildonTouchSelector
2454  * @column: column number
2455  *
2456  * Gets a #GtkTreePath of the last row activated in a column (the last row that
2457  * emitted a #GtkTreeView::row-activated signal). This is mainly useful if the
2458  * @selector #HildonTouchSelector:hildon-ui-mode in set to %HILDON_UI_MODE_NORMAL,
2459  * as using this state there is no real selection, so a method like
2460  * hildon_touch_selector_get_selected_rows() will return always a empty
2461  * selection.
2462  *
2463  * Anyway, this method works as well on %HILDON_UI_MODE_EDIT, but in this case
2464  * is better, and more useful, to get the current selection.
2465  *
2466  * Returns: a newly allocated #GtkTreePath pointing to the last activated row
2467  *          NULL if no row were activated.
2468  *
2469  * Since: 2.2
2470  **/
2471 GtkTreePath*
2472 hildon_touch_selector_get_last_activated_row    (HildonTouchSelector *selector,
2473                                                  gint                 column)
2474 {
2475   HildonTouchSelectorColumn *selector_column = NULL;
2476
2477   /* this method with check selector and that the column number is correct*/
2478   selector_column = hildon_touch_selector_get_column (selector, column);
2479
2480   if (selector_column == NULL) {
2481     return NULL;
2482   }
2483
2484   if (selector_column->priv->last_activated != NULL) {
2485     return gtk_tree_row_reference_get_path (selector_column->priv->last_activated);
2486   } else {
2487     return NULL;
2488   }
2489 }
2490
2491
2492 /**
2493  * hildon_touch_selector_center_on_index:
2494  * @selector: a #HildonTouchSelector
2495  * @column: column number
2496  * @index: the index of the item to center on
2497  *
2498  * Ensures that the column number @column shows the element @index
2499  *
2500  * This is similar to hildon_touch_selector_center_on_selected() but with the
2501  * difference that allows to center on a column item not selected.
2502  *
2503  * Take into account that the element is not centered until the widget is
2504  * realized. If the widget is not realized when the function is called, it will
2505  * be postponed. If you call this function several times before the widget is
2506  * realized, only the last one will be used.
2507  *
2508  * This behaviour includes any call to hildon_touch_selector_center_on_selected().
2509  * Check this function for more tips.
2510  *
2511  * Since: 2.2
2512  **/
2513 void
2514 hildon_touch_selector_center_on_index (HildonTouchSelector *selector,
2515                                        gint column,
2516                                        gint index)
2517 {
2518   HildonTouchSelectorColumn *current_column = NULL;
2519   GtkTreePath *path = NULL;
2520
2521   g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
2522   g_return_if_fail ((column >= 0) && (column < hildon_touch_selector_get_num_columns (selector)));
2523   g_return_if_fail (index >= 0);
2524
2525   current_column = g_slist_nth_data (selector->priv->columns, column);
2526
2527   path = gtk_tree_path_new_from_indices (index, -1);
2528
2529   hildon_touch_selector_scroll_to (current_column,
2530                                    current_column->priv->tree_view,
2531                                    path);
2532   gtk_tree_path_free (path);
2533 }