2008-07-29 Claudio Saavedra <csaavedra@igalia.com>
[hildon] / src / hildon-touch-picker.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-picker
23  * @short_description: A picker widget with several columns
24  *
25  * HildonTouchPicker is a picker widget, very similar to the #GtkComboBox, but with
26  * several individual pannable columns
27  *
28  */
29
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33
34 #include <string.h>
35 #include <stdlib.h>
36 #include "hildon-pannable-area.h"
37 #include "hildon-touch-picker.h"
38
39 #define HILDON_TOUCH_PICKER_GET_PRIVATE(obj)\
40   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), HILDON_TYPE_TOUCH_PICKER, HildonTouchPickerPrivate))
41
42 G_DEFINE_TYPE (HildonTouchPicker, hildon_touch_picker, GTK_TYPE_HBOX)
43
44 #define CENTER_ON_SELECTED_ITEM_DELAY 50
45
46 /**
47  * Struct to maintain the data of each column. The columns are the elements
48  * of the widget that belongs properly to the selection behaviour. As
49  * the picker is a hbox, you can add more widgets, like buttons etc.
50  * between the columns, but this doesn't belongs to the selection
51  * logic
52  */
53 typedef struct _PickerColumn PickerColumn;
54 struct _PickerColumn
55 {
56   HildonTouchPicker *parent;    /* the picker that contains this column */
57   GtkTreeModel *model;
58   GtkTreeView *tree_view;
59
60   GtkWidget *panarea;           /* the pannable widget */
61 };
62
63 struct _HildonTouchPickerPrivate
64 {
65   GSList *columns;              /* the selection columns */
66
67   HildonTouchPickerPrintFunc print_func;
68 };
69
70 enum
71 {
72   CHANGED,
73   LAST_SIGNAL
74 };
75
76 static gint hildon_touch_picker_signals[LAST_SIGNAL] = { 0 };
77
78 /* gtkwidget */
79 static void hildon_touch_picker_map (GtkWidget * widget);
80
81 /* gtkcontainer */
82 static void hildon_touch_picker_remove (GtkContainer * container,
83                                         GtkWidget * widget);
84 /* private functions */
85 static void _selection_changed_cb (GtkTreeSelection * selection,
86                                    gpointer user_data);
87 static gchar *_default_print_func (HildonTouchPicker * picker);
88
89 static PickerColumn *_create_new_column (HildonTouchPicker * picker,
90                                          GtkTreeModel * model,
91                                          GtkCellRenderer * renderer,
92                                          va_list args);
93 static gboolean _hildon_touch_picker_center_on_selected_items (gpointer data);
94
95 static void
96 hildon_touch_picker_class_init (HildonTouchPickerClass * class)
97 {
98   GObjectClass *gobject_class;
99   GtkObjectClass *object_class;
100   GtkWidgetClass *widget_class;
101   GtkContainerClass *container_class;
102
103   gobject_class = (GObjectClass *) class;
104   object_class = (GtkObjectClass *) class;
105   widget_class = (GtkWidgetClass *) class;
106   container_class = (GtkContainerClass *) class;
107
108   /* GObject */
109
110   /* GtkWidget */
111   widget_class->map = hildon_touch_picker_map;
112
113   /* GtkContainer */
114   container_class->remove = hildon_touch_picker_remove;
115
116
117   /* signals */
118   /**
119    * HildonTouchPicker::changed:
120    * @widget: the object which received the signal
121    *
122    * The changed signal is emitted when the active
123    * item is changed. The can be due to the user selecting
124    * a different item from the list, or due to a
125    * call to hildon_touch_picker_set_active_iter() on
126    * one of the columns
127    *
128    */
129   hildon_touch_picker_signals[CHANGED] =
130     g_signal_new ("changed",
131                   G_OBJECT_CLASS_TYPE (class),
132                   G_SIGNAL_RUN_LAST,
133                   G_STRUCT_OFFSET (HildonTouchPickerClass, changed),
134                   NULL, NULL,
135                   gtk_marshal_NONE__INT, G_TYPE_NONE, 1, G_TYPE_INT);
136   /* properties */
137
138   /* style properties */
139   g_type_class_add_private (object_class, sizeof (HildonTouchPickerPrivate));
140 }
141
142
143 static void
144 hildon_touch_picker_init (HildonTouchPicker * picker)
145 {
146   picker->priv = HILDON_TOUCH_PICKER_GET_PRIVATE (picker);
147
148   GTK_WIDGET_SET_FLAGS (GTK_WIDGET (picker), GTK_NO_WINDOW);
149   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (picker), FALSE);
150
151   picker->priv->columns = NULL;
152
153   picker->priv->print_func = NULL;
154
155   /* FIXME: this is the correct height? A fixed height is the correct 
156      implementation */
157   gtk_widget_set_size_request (GTK_WIDGET (picker), -1, 320);
158 }
159
160 static void
161 hildon_touch_picker_map (GtkWidget * widget)
162 {
163   GTK_WIDGET_CLASS (hildon_touch_picker_parent_class)->map (widget);
164
165   g_timeout_add (CENTER_ON_SELECTED_ITEM_DELAY,
166                  _hildon_touch_picker_center_on_selected_items, widget);
167 }
168
169 /*------------------------------ GtkContainer ------------------------------ */
170
171 /*
172  * Required in order to free the column at the columns list
173  */
174 static void
175 hildon_touch_picker_remove (GtkContainer * container, GtkWidget * widget)
176 {
177   HildonTouchPicker *picker = NULL;
178   GSList *iter = NULL;
179   gint position = 0;
180   PickerColumn *current_column = NULL;
181   gint num_columns = 0;
182
183   g_return_if_fail (HILDON_IS_TOUCH_PICKER (container));
184
185   picker = HILDON_TOUCH_PICKER (container);
186   num_columns = hildon_touch_picker_get_num_columns (picker);
187
188   /* Check if the widget is inside a column and remove
189      it from the list */
190   iter = picker->priv->columns;
191   position = 0;
192   while (iter) {
193     current_column = (PickerColumn *) iter->data;
194     if (widget == current_column->panarea) {
195       current_column = g_slist_nth_data (picker->priv->columns, position);
196
197       picker->priv->columns = g_slist_remove (picker->priv->columns,
198                                               current_column);
199       g_free (current_column);
200
201       break;
202     }
203
204     position++;
205     iter = g_slist_next (iter);
206   }
207   if (position >= num_columns) {
208     g_debug ("This widget was not inside the picker column");
209   }
210
211   GTK_CONTAINER_CLASS (hildon_touch_picker_parent_class)->remove (container, widget);
212 }
213
214 /* ------------------------------ PRIVATE METHODS ---------------------------- */
215 /**
216  * default_print_func:
217  * @picker: a #HildonTouchPicker
218  *
219  * Default print function
220  *
221  * Returns: a new string that represent the selected items
222  **/
223 static gchar *
224 _default_print_func (HildonTouchPicker * picker)
225 {
226   gchar *result = NULL;
227   gchar *aux = NULL;
228   gint num_columns = 0;
229   GtkTreeIter iter;
230   GtkTreeModel *model = NULL;
231   gchar *current_string = NULL;
232   gint i;
233   HildonTouchPickerSelectionMode mode;
234   GList *item = NULL;
235   GtkTreePath *current_path = NULL;
236   GList *selected_rows = NULL;
237   gint initial_value = 0;
238
239   num_columns = hildon_touch_picker_get_num_columns (picker);
240
241   mode = hildon_touch_picker_get_column_selection_mode (picker);
242
243   if ((mode == HILDON_TOUCH_PICKER_SELECTION_MODE_MULTIPLE)
244       && (num_columns > 0)) {
245     /* In this case we get the first column first */
246     selected_rows = hildon_touch_picker_get_selected_rows (picker, 0);
247     model = hildon_touch_picker_get_model (picker, 0);
248
249     result = g_strdup_printf ("(");
250     i = 0;
251     for (item = selected_rows; item; item = g_list_next (item)) {
252       current_path = item->data;
253       gtk_tree_model_get_iter (model, &iter, current_path);
254
255       gtk_tree_model_get (model, &iter, 0, &current_string, -1);
256
257       if (i < g_list_length (selected_rows) - 1) {
258         aux = g_strconcat (result, current_string, ",", NULL);
259         g_free (result);
260         result = aux;
261       } else {
262         aux = g_strconcat (result, current_string, NULL);
263         g_free (result);
264         result = aux;
265       }
266       i++;
267     }
268
269     aux = g_strconcat (result, ")", NULL);
270     g_free (result);
271     result = aux;
272
273     g_list_foreach (selected_rows, (GFunc) (gtk_tree_path_free), NULL);
274     g_list_free (selected_rows);
275     initial_value = 1;
276   } else {
277     initial_value = 0;
278   }
279
280   for (i = initial_value; i < num_columns; i++) {
281     model = hildon_touch_picker_get_model (picker, i);
282     if (hildon_touch_picker_get_active_iter (picker, i, &iter)) {
283
284       gtk_tree_model_get (model, &iter, 0, &current_string, -1);
285       if (i != 0) {
286         aux = g_strconcat (result, ":", current_string, NULL);
287         g_free (result);
288         result = aux;
289       } else {
290         result = g_strdup_printf ("%s", current_string);
291       }
292     }
293   }
294
295   return result;
296 }
297
298 static void
299 _selection_changed_cb (GtkTreeSelection * selection, gpointer user_data)
300 {
301   HildonTouchPicker *picker = NULL;
302   PickerColumn *column = NULL;
303   gint num_column = -1;
304
305   column = (PickerColumn *) user_data;
306   g_return_if_fail (HILDON_IS_TOUCH_PICKER (column->parent));
307
308   picker = column->parent;
309
310   num_column = g_slist_index (picker->priv->columns, column);
311
312   g_signal_emit (picker, hildon_touch_picker_signals[CHANGED], 0, num_column);
313 }
314
315
316 static PickerColumn *
317 _create_new_column (HildonTouchPicker * picker,
318                     GtkTreeModel * model,
319                     GtkCellRenderer * renderer, va_list args)
320 {
321   PickerColumn *new_column = NULL;
322   GtkTreeViewColumn *tree_column = NULL;
323   GValue val = { 0, };
324   GtkTreeView *tv = NULL;
325   GtkWidget *panarea = NULL;
326   GtkTreeSelection *selection = NULL;
327   GtkTreeIter iter;
328   gchar *attribute;
329   gint value;
330
331   tree_column = gtk_tree_view_column_new ();
332   gtk_tree_view_column_pack_start (tree_column, renderer, TRUE);
333
334   attribute = va_arg (args, gchar *);
335   while (attribute != NULL) {
336     value = va_arg (args, gint);
337     gtk_tree_view_column_add_attribute (tree_column, renderer, attribute,
338                                         value);
339     attribute = va_arg (args, gchar *);
340   }
341
342   tv = g_object_new (GTK_TYPE_TREE_VIEW, "model", model, "name", "fremantle-widget",    /* FIXME: is this always this name? */
343                      "hildon-ui-mode", HILDON_UI_MODE_EDIT,
344                      "rules-hint", TRUE, NULL);
345
346   gtk_tree_view_append_column (GTK_TREE_VIEW (tv), tree_column);
347
348   new_column = (PickerColumn *) g_malloc0 (sizeof (PickerColumn));
349   new_column->parent = picker;
350
351   panarea = hildon_pannable_area_new ();
352
353   g_value_init (&val, G_TYPE_INT);
354   g_value_set_int (&val, HILDON_PANNABLE_AREA_INDICATOR_MODE_HIDE);
355   g_object_set_property (G_OBJECT (panarea), "vindicator-mode", &val);
356
357   g_value_unset (&val);
358   g_value_init (&val, G_TYPE_BOOLEAN);
359   g_value_set_boolean (&val, FALSE);
360   g_object_set_property (G_OBJECT (panarea), "initial-hint", &val);
361
362   gtk_container_add (GTK_CONTAINER (panarea), GTK_WIDGET (tv));
363
364   new_column->model = model;
365   new_column->tree_view = tv;
366   new_column->panarea = panarea;
367
368   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
369   gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
370
371   /* select the first item */
372   if (gtk_tree_model_get_iter_first (model, &iter)) {
373     gtk_tree_selection_select_iter (selection, &iter);
374   }
375
376   gtk_widget_grab_focus (GTK_WIDGET (tv));
377
378   /* connect to the changed signal connection */
379   g_signal_connect (G_OBJECT (selection), "changed",
380                     G_CALLBACK (_selection_changed_cb), new_column);
381
382   return new_column;
383 }
384
385 /* ------------------------------ PUBLIC METHODS ---------------------------- */
386
387 /**
388  * hildon_touch_picker_new:
389  * @:
390  *
391  * Creates a new empty #HildonTouchPicker
392  *
393  * Returns: a new #HildonTouchPicker
394  **/
395 GtkWidget *
396 hildon_touch_picker_new ()
397 {
398   return g_object_new (HILDON_TYPE_TOUCH_PICKER, NULL);
399 }
400
401 /**
402  * hildon_touch_picker_append_text_column
403  * @picker: the #HildonTouchPicker widget
404  * @model: the #GtkTreeModel with the data of the column
405  *
406  * This functions adds a new column to the widget, with the data on
407  * the model. Only the widgets added in this way should used on
408  * the selection logic, ie: the print function, the "changed" signal etc.
409  *
410  * There are a prerequisite on this model: this append
411  * consideres that the text data is in the first column of the model
412  *
413  * Basically it adds a tree view to the widget, using the model and
414  * the data received.
415  *
416  * Returns: TRUE if a new column were added, FALSE otherside
417  **/
418 gboolean
419 hildon_touch_picker_append_column (HildonTouchPicker * picker,
420                                    GtkTreeModel * model,
421                                    GtkCellRenderer * cell_renderer, ...)
422 {
423   va_list args;
424   PickerColumn *new_column = NULL;
425
426   g_return_val_if_fail (HILDON_IS_TOUCH_PICKER (picker), FALSE);
427   g_return_val_if_fail (GTK_IS_TREE_MODEL (model), FALSE);
428
429   if (model != NULL) {
430
431     va_start (args, cell_renderer);
432     new_column = _create_new_column (picker, model, cell_renderer, args);
433     va_end (args);
434
435     picker->priv->columns = g_slist_append (picker->priv->columns,
436                                             new_column);
437     gtk_box_pack_start (GTK_BOX (picker), new_column->panarea, TRUE, TRUE, 6);
438
439     gtk_widget_show_all (new_column->panarea);
440   } else {
441     return FALSE;
442   }
443
444   return TRUE;
445 }
446
447 /**
448  * hildon_touch_picker_append_text_column
449  * @picker: the #HildonTouchPicker widget
450  * @model: the #GtkTreeModel with the data of the column
451  *
452  * Equivalent to hildon_touch_picker_append_column, but using a
453  * default text cell renderer. This is the most common use of the
454  * widget.
455  *
456  * Returns: TRUE if a new column were added, FALSE otherside
457  **/
458 gboolean
459 hildon_touch_picker_append_text_column (HildonTouchPicker * picker,
460                                         GtkTreeModel * model)
461 {
462   GtkCellRenderer *renderer = NULL;
463   GValue val = { 0, };
464
465   g_return_val_if_fail (HILDON_IS_TOUCH_PICKER (picker), FALSE);
466   g_return_val_if_fail (GTK_IS_TREE_MODEL (model), FALSE);
467
468   if (model != NULL) {
469     renderer = gtk_cell_renderer_text_new ();
470
471     g_value_init (&val, G_TYPE_FLOAT);
472     g_value_set_float (&val, 0.5);
473     /* FIXME: center the text, this should be configurable */
474     g_object_set_property (G_OBJECT (renderer), "xalign", &val);
475
476     return hildon_touch_picker_append_column (picker, model, renderer,
477                                               "text", 0, NULL);
478   } else {
479     return FALSE;
480   }
481 }
482
483 /**
484  * hildon_touch_picker_remove_column
485  * @picker: a #HildonTouchPicker
486  * @position: the column position to remove, counting from 0 to (total column number - 1)
487  *
488  *
489  * Returns: TRUE is the column was removed, FALSE otherwise
490  **/
491 gboolean
492 hildon_touch_picker_remove_column (HildonTouchPicker * picker, gint position)
493 {
494   PickerColumn *current_column = NULL;
495
496   g_return_val_if_fail (HILDON_IS_TOUCH_PICKER (picker), FALSE);
497   g_return_val_if_fail (position <
498                         hildon_touch_picker_get_num_columns (picker), FALSE);
499
500   current_column = g_slist_nth_data (picker->priv->columns, position);
501
502   gtk_container_remove (GTK_CONTAINER (picker), current_column->panarea);
503
504   return TRUE;
505 }
506
507 void
508 hildon_touch_picker_set_column_attributes (HildonTouchPicker * picker,
509                                            gint num_column,
510                                            GtkCellRenderer * cell_renderer,
511                                            ...)
512 {
513   va_list args;
514   GtkTreeViewColumn *tree_column = NULL;
515   PickerColumn *current_column = NULL;
516   gchar *attribute = NULL;
517   gint value = 0;
518
519   g_return_if_fail (HILDON_IS_TOUCH_PICKER (picker));
520   g_return_if_fail (num_column <
521                     hildon_touch_picker_get_num_columns (picker));
522
523   current_column = g_slist_nth_data (picker->priv->columns, num_column);
524
525   tree_column = gtk_tree_view_get_column (current_column->tree_view, 0);
526   gtk_tree_view_remove_column (current_column->tree_view, tree_column);
527
528   tree_column = gtk_tree_view_column_new ();
529   gtk_tree_view_column_pack_start (tree_column, cell_renderer, TRUE);
530
531   va_start (args, cell_renderer);
532   attribute = va_arg (args, gchar *);
533
534   gtk_tree_view_column_clear_attributes (tree_column, cell_renderer);
535
536   while (attribute != NULL) {
537     value = va_arg (args, gint);
538     gtk_tree_view_column_add_attribute (tree_column, cell_renderer,
539                                         attribute, value);
540     attribute = va_arg (args, gchar *);
541   }
542
543   va_end (args);
544
545   gtk_tree_view_append_column (current_column->tree_view, tree_column);
546 }
547
548 gboolean
549 hildon_touch_picker_insert_column (HildonTouchPicker * picker, gint position)
550 {
551   g_warning ("Un-implemented!");
552
553   return TRUE;
554 }
555
556 gint
557 hildon_touch_picker_get_num_columns (HildonTouchPicker * picker)
558 {
559   return g_slist_length (picker->priv->columns);
560 }
561
562 HildonTouchPickerSelectionMode
563 hildon_touch_picker_get_column_selection_mode (HildonTouchPicker * picker)
564 {
565   HildonTouchPickerSelectionMode result =
566     HILDON_TOUCH_PICKER_SELECTION_MODE_SINGLE;
567   GtkSelectionMode treeview_mode = GTK_SELECTION_SINGLE;
568   PickerColumn *column = NULL;
569   GtkTreeSelection *selection = NULL;
570
571   g_return_val_if_fail (HILDON_IS_TOUCH_PICKER (picker), result);
572   g_return_val_if_fail (hildon_touch_picker_get_num_columns (picker) > 0,
573                         result);
574
575   column = (PickerColumn *) picker->priv->columns->data;
576
577   selection = gtk_tree_view_get_selection (column->tree_view);
578   treeview_mode = gtk_tree_selection_get_mode (selection);
579
580
581   if (treeview_mode == GTK_SELECTION_MULTIPLE) {
582     result = HILDON_TOUCH_PICKER_SELECTION_MODE_MULTIPLE;
583   } else {
584     result = HILDON_TOUCH_PICKER_SELECTION_MODE_SINGLE;
585   }
586
587   return result;
588 }
589
590 void
591 hildon_touch_picker_set_column_selection_mode (HildonTouchPicker * picker,
592                                                HildonTouchPickerSelectionMode
593                                                mode)
594 {
595   GtkTreeView *tv = NULL;
596   PickerColumn *column = NULL;
597   GtkTreeSelection *selection = NULL;
598   GtkSelectionMode treeview_mode;
599   GtkTreeIter iter;
600
601   g_return_if_fail (HILDON_IS_TOUCH_PICKER (picker));
602   g_return_if_fail (hildon_touch_picker_get_num_columns (picker) > 0);
603
604   column = (PickerColumn *) (g_slist_nth (picker->priv->columns, 0))->data;
605   tv = column->tree_view;
606
607   if (tv) {
608     switch (mode) {
609     case HILDON_TOUCH_PICKER_SELECTION_MODE_SINGLE:
610       treeview_mode = GTK_SELECTION_SINGLE;
611       break;
612     case HILDON_TOUCH_PICKER_SELECTION_MODE_MULTIPLE:
613       treeview_mode = GTK_SELECTION_MULTIPLE;
614       break;
615     }
616
617     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
618     gtk_tree_selection_set_mode (selection, treeview_mode);
619
620     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
621     gtk_tree_model_get_iter_first (column->model, &iter);
622     gtk_tree_selection_unselect_all (selection);
623     gtk_tree_selection_select_iter (selection, &iter);
624   }
625
626 }
627
628 void
629 hildon_touch_picker_set_print_func (HildonTouchPicker * picker,
630                                     HildonTouchPickerPrintFunc func)
631 {
632   g_return_if_fail (HILDON_IS_TOUCH_PICKER (picker));
633
634   picker->priv->print_func = func;
635 }
636
637 HildonTouchPickerPrintFunc
638 hildon_touch_picker_get_print_func (HildonTouchPicker * picker)
639 {
640   g_return_val_if_fail (HILDON_IS_TOUCH_PICKER (picker), NULL);
641
642   return picker->priv->print_func;
643 }
644
645 /**
646  * hildon_touch_picker_get_active_iter:
647  * @picker: a #HildonTouchPicker
648  * @column: the column number we want to get the element
649  * @iter: #GtkTreeIter currently selected
650  *
651  * Sets iter to the currently selected node on the nth-column, if selection is set to
652  * HILDON_TOUCH_PICKER_SINGLE. iter may be NULL if you just want to test if selection
653  * has any selected nodes.
654  *
655  * This function will not work if you use selection is HILDON_TOUCH_PICKER_MULTIPLE.
656  *
657  * See gtk_tree_selection_get_selected for more information
658  *
659  * Returns: TRUE if was posible to get the iter, FALSE otherwise
660  **/
661 gboolean
662 hildon_touch_picker_get_active_iter (HildonTouchPicker * picker,
663                                      gint column, GtkTreeIter * iter)
664 {
665   GtkTreeSelection *selection = NULL;
666   PickerColumn *current_column = NULL;
667
668   g_return_val_if_fail (HILDON_IS_TOUCH_PICKER (picker), FALSE);
669   g_return_val_if_fail (hildon_touch_picker_get_column_selection_mode (picker)
670                         == HILDON_TOUCH_PICKER_SELECTION_MODE_SINGLE, FALSE);
671   g_return_val_if_fail (column < hildon_touch_picker_get_num_columns (picker),
672                         FALSE);
673
674   current_column = g_slist_nth_data (picker->priv->columns, column);
675
676   selection =
677     gtk_tree_view_get_selection (GTK_TREE_VIEW (current_column->tree_view));
678
679   return gtk_tree_selection_get_selected (selection, NULL, iter);
680 }
681
682 /**
683  * hildon_touch_picker_set_active_iter
684  * @picker: a #HildonTouchPicker
685  * @column:   the column to selects
686  * @iter:     the #GtkTreeIter to be selected
687  *
688  * Sets the current iter
689  *
690  **/
691 void
692 hildon_touch_picker_set_active_iter (HildonTouchPicker * picker,
693                                      gint column, GtkTreeIter * iter,
694                                      gboolean scroll_to)
695 {
696   GtkTreePath *path;
697   GtkTreeModel *model;
698   GdkRectangle rect;
699   PickerColumn *current_column = NULL;
700   GtkTreeSelection *selection = NULL;
701   gint y;
702
703   g_return_if_fail (HILDON_IS_TOUCH_PICKER (picker));
704   g_return_if_fail (column < hildon_touch_picker_get_num_columns (picker));
705
706   current_column = g_slist_nth_data (picker->priv->columns, column);
707
708   selection = gtk_tree_view_get_selection (current_column->tree_view);
709
710   gtk_tree_selection_select_iter (selection, iter);
711
712   if (scroll_to) {
713     model = gtk_tree_view_get_model (current_column->tree_view);
714     path = gtk_tree_model_get_path (model, iter);
715     gtk_tree_view_get_background_area (current_column->tree_view,
716                                        path, NULL, &rect);
717     gtk_tree_view_convert_bin_window_to_tree_coords (current_column->tree_view,
718                                                      0, rect.y, NULL, &y);
719     hildon_pannable_area_scroll_to (HILDON_PANNABLE_AREA (current_column->panarea),
720                                     -1, y);
721     gtk_tree_path_free (path);
722   }
723 }
724
725 /**
726  * hildon_touch_picker_get_selected_rows:
727  * @picker: a #HildonTouchPicker
728  * @column:
729  *
730  * Creates a list of path of all selected rows at a concrete column. Additionally,
731  * if you are planning on modifying the model after calling this function, you may
732  * want to convert the returned list into a list of GtkTreeRowReferences. To do this,
733  * you can use gtk_tree_row_reference_new().
734  *
735  * See #GtkTreeSelection:gtk_tree_selection_get_selected_rows for more information
736  *
737  * Returns: A new GList containing a GtkTreePath for each selected row in the concrete column
738  *
739  **/
740 GList *
741 hildon_touch_picker_get_selected_rows (HildonTouchPicker * picker,
742                                        gint column)
743 {
744   GList *result = NULL;
745   PickerColumn *current_column = NULL;
746   GtkTreeSelection *selection = NULL;
747
748   g_return_val_if_fail (HILDON_IS_TOUCH_PICKER (picker), NULL);
749   g_return_val_if_fail (column < hildon_touch_picker_get_num_columns (picker),
750                         NULL);
751
752   current_column = g_slist_nth_data (picker->priv->columns, column);
753   selection = gtk_tree_view_get_selection (current_column->tree_view);
754
755   result = gtk_tree_selection_get_selected_rows (selection, NULL);
756
757
758   return result;
759 }
760
761 GtkTreeModel *
762 hildon_touch_picker_get_model (HildonTouchPicker * picker, gint column)
763 {
764   PickerColumn *current_column = NULL;
765
766   g_return_val_if_fail (HILDON_IS_TOUCH_PICKER (picker), NULL);
767   g_return_val_if_fail (column < hildon_touch_picker_get_num_columns (picker),
768                         NULL);
769
770   current_column = g_slist_nth_data (picker->priv->columns, column);
771
772   return current_column->model;
773 }
774
775 void
776 hildon_touch_picker_set_model (HildonTouchPicker * picker,
777                                gint num_column, GtkTreeModel * model)
778 {
779   PickerColumn *column = NULL;
780
781   g_return_if_fail (HILDON_TOUCH_PICKER (picker));
782   g_return_if_fail (num_column <
783                     hildon_touch_picker_get_num_columns (picker));
784
785   column =
786     (PickerColumn *) g_slist_nth_data (picker->priv->columns, num_column);
787
788   column->model = model;
789   gtk_tree_view_set_model (column->tree_view, column->model);
790 }
791
792 /**
793  * hildon_touch_picker_get_active_text
794  * @picker: the #HildonTouchPicker
795  *
796  * It return a new gchar that represents the current element(s) selected,
797  * using the current print_func.
798  *
799  * Returns: a new allocated gchar*
800  **/
801 gchar *
802 hildon_touch_picker_get_current_text (HildonTouchPicker * picker)
803 {
804   gchar *result = NULL;
805   g_return_val_if_fail (HILDON_IS_TOUCH_PICKER (picker), NULL);
806
807   if (picker->priv->print_func) {
808     result = (*picker->priv->print_func) (picker);
809   } else {
810     result = _default_print_func (picker);
811   }
812
813   return result;
814 }
815
816 static gboolean
817 _hildon_touch_picker_center_on_selected_items (gpointer data)
818 {
819   HildonTouchPicker *picker = NULL;
820   PickerColumn *column = NULL;
821   GSList *iter_column = NULL;
822   GtkTreeIter iter;
823   GtkTreePath *path;
824   GdkRectangle rect;
825   gint y;
826   gint i;
827   HildonTouchPickerSelectionMode selection_mode;
828
829   /* ensure to center on the initial values */
830   picker = HILDON_TOUCH_PICKER (data);
831
832   selection_mode = hildon_touch_picker_get_column_selection_mode (picker);
833
834   iter_column = picker->priv->columns;
835   i = 0;
836   while (iter_column) {
837     column = (PickerColumn *) iter_column->data;
838
839     if ((i == 0)
840         && (selection_mode == HILDON_TOUCH_PICKER_SELECTION_MODE_MULTIPLE)) {
841       break;
842     }
843     if (hildon_touch_picker_get_active_iter (picker, i, &iter)) {
844       path = gtk_tree_model_get_path (column->model, &iter);
845       gtk_tree_view_get_background_area (GTK_TREE_VIEW
846                                          (column->tree_view), path, NULL,
847                                          &rect);
848
849       gtk_tree_view_convert_bin_window_to_tree_coords (GTK_TREE_VIEW
850                                                        (column->tree_view), 0,
851                                                        rect.y, NULL, &y);
852
853       hildon_pannable_area_scroll_to (HILDON_PANNABLE_AREA
854                                       (column->panarea), -1, y);
855
856       gtk_tree_path_free (path);
857     }
858     iter_column = iter_column->next;
859     i++;
860   }
861
862   return FALSE;
863 }