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