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