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