2008-12-11 Claudio Saavedra <csaavedra@igalia.com>
[hildon] / src / hildon-sort-dialog.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2005, 2006 Nokia Corporation, all rights reserved.
5  *
6  * Contact: Rodrigo Novo <rodrigo.novo@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24
25 /** 
26  * SECTION:hildon-sort-dialog
27  * @short_description: A widget for defining the sorting order of items.
28  * 
29  * HildonSortDialog is used to define an order (ascending/descending)
30  * and a field by which items are sorted in a list. The combo boxes
31  * display the current value when the dialog is opened.
32  *
33  * <example>
34  * <title>An example for using HildonSortDialog</title>
35  * <programlisting>
36  * HildonSortDialog *sort_dialog = HILDON_SORT_DIALOG (hildon_sort_dialog_new (parent));
37  * <!-- -->
38  * gint response_id, add_sort_index;
39  * <!-- -->
40  * sort_by[0] = STR_SORT_BY_DATE;
41  * sort_by[1] = STR_SORT_BY_NAME;
42  * sort_by[2] = STR_SORT_BY_SIZE;
43  * sort_by[3] = NULL;
44  * <!-- -->
45  * sorting_order[0] = STR_SORTING_ORDER_ASCENDING;
46  * sorting_order[1] = STR_SORTING_ORDER_DESCENDING;
47  * sorting_order[2] = NULL;
48  * <!-- -->
49  * add_sort_index = hildon_sort_dialog_add_sort_key (sort_dialog, STR_SORT_BY_DATE);
50  * <!-- -->
51  * hildon_sort_dialog_add_sort_key (sort_dialog, STR_SORT_BY_NAME);
52  * <!-- -->
53  * hildon_sort_dialog_add_sort_key (sort_dialog, STR_SORT_BY_SIZE);
54  * <!-- -->
55  * if (dialog.first_time_clicked == TRUE)
56  * {
57  *      hildon_sort_dialog_set_sort_key (sort_dialog, add_sort_index);
58  * }
59  * <!-- -->
60  * if (dialog.first_time_clicked == FALSE)
61  * {
62  *      hildon_sort_dialog_set_sort_key (sort_dialog, dialog.sort_key);
63  *      hildon_sort_dialog_set_sort_order (sort_dialog, dialog.sort_order);
64  * }
65  * <!-- -->
66  * gtk_widget_show (GTK_WIDGET (sort_dialog));
67  * <!-- -->
68  * response_id = gtk_dialog_run (GTK_DIALOG (sort_dialog));
69  * <!-- -->
70  * if (response_id == GTK_RESPONSE_OK)
71  * {
72  *      dialog.sort_key = hildon_sort_dialog_get_sort_key (sort_dialog);
73  * <!-- -->
74  *      gtk_label_set_text (GTK_LABEL (dialog.label1), sort_by [dialog.sort_key]);
75  * <!-- -->
76  *      dialog.sort_order = hildon_sort_dialog_get_sort_order (sort_dialog);
77  * <!-- -->
78  *      gtk_label_set_text (GTK_LABEL (dialog.label2), sorting_order [dialog.sort_order]);
79  * <!-- -->
80  *      dialog.first_time_clicked = FALSE;
81  * }
82  * </programlisting>
83  * </example>
84  */
85
86 #undef                                          HILDON_DISABLE_DEPRECATED
87
88 #ifdef                                          HAVE_CONFIG_H
89 #include                                        <config.h>
90 #endif
91
92 #include                                        <stdio.h>
93 #include                                        <libintl.h>
94
95 #include                                        "hildon-sort-dialog.h"
96 #include                                        "hildon-caption.h"
97 #include                                        "hildon-sort-dialog-private.h"
98
99 #define                                         _(String) \
100                                                 dgettext("hildon-libs", String)
101
102 static GtkDialogClass*                          parent_class;
103
104 static void 
105 hildon_sort_dialog_class_init                   (HildonSortDialogClass *class);
106
107 static void
108 hildon_sort_dialog_init                         (HildonSortDialog *widget);
109
110 static void 
111 hildon_sort_dialog_set_property                 (GObject * object,
112                                                  guint prop_id,
113                                                  const GValue *value,
114                                                  GParamSpec * pspec);
115
116 static void 
117 hildon_sort_dialog_get_property                 (GObject *object,
118                                                  guint prop_id,
119                                                  GValue * value, 
120                                                  GParamSpec * pspec);
121
122 static void 
123 reconstruct_combo                               (HildonSortDialog *dialog, 
124                                                  gboolean remove, 
125                                                  gboolean reversed);
126
127 static void
128 sort_key_changed                                (GtkWidget *widget, 
129                                                  HildonSortDialog *dialog);
130
131 static void 
132 hildon_sort_dialog_finalize                     (GObject *object);
133
134 static gint 
135 hildon_sort_dialog_add_sort_key_with_sorting    (HildonSortDialog *dialog, 
136                                                  const gchar *sort_key, 
137                                                  gboolean sorting);
138
139 enum 
140 {
141     PROP_0,
142     PROP_SORT_KEY,
143     PROP_SORT_ORDER
144 };
145
146 static void 
147 sort_key_changed                                (GtkWidget *widget, 
148                                                  HildonSortDialog *dialog)
149 {
150     g_return_if_fail (HILDON_IS_SORT_DIALOG (dialog));
151
152     HildonSortDialogPrivate *priv = HILDON_SORT_DIALOG_GET_PRIVATE (dialog);
153     g_assert (priv);
154
155     gint index = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
156
157     if (priv->key_reversed [index] != priv->reversed) {
158         reconstruct_combo (dialog, TRUE, priv->key_reversed [index]);
159         gtk_combo_box_set_active (GTK_COMBO_BOX (priv->combo_order), 0);
160     }
161
162     priv->reversed = priv->key_reversed [index];
163 }
164
165 /* Initialises the sort dialog class. */
166 static void
167 hildon_sort_dialog_class_init                   (HildonSortDialogClass *class)
168 {
169     GObjectClass *gobject_class = G_OBJECT_CLASS (class);
170     parent_class = g_type_class_peek_parent (class);
171     g_type_class_add_private (class, sizeof (HildonSortDialogPrivate));
172     
173     gobject_class->set_property = hildon_sort_dialog_set_property;
174     gobject_class->get_property = hildon_sort_dialog_get_property;
175     gobject_class->finalize     = (gpointer) hildon_sort_dialog_finalize;
176
177     /**
178      * HildonSortDialog:sort-key:
179      *
180      * The currently active sort key.
181      */
182     g_object_class_install_property (gobject_class, PROP_SORT_KEY,
183         g_param_spec_int ("sort-key",
184                           "Sort Key",
185                           "The currently active sort key",
186                           G_MININT,
187                           G_MAXINT,
188                           0, G_PARAM_READWRITE));
189    
190     /**
191      * HildonSortDialog:sort-order:
192      *
193      * The sort order for the currently active sort key.
194      */
195     g_object_class_install_property (gobject_class, PROP_SORT_ORDER,
196         g_param_spec_enum ("sort-order",
197                           "Sort Order",
198                           "The current sorting order",
199                           GTK_TYPE_SORT_TYPE,
200                           GTK_SORT_ASCENDING,
201                           G_PARAM_READWRITE));
202 }
203
204 static gint 
205 hildon_sort_dialog_add_sort_key_with_sorting    (HildonSortDialog *dialog, 
206                                                  const gchar *sort_key, 
207                                                  gboolean sorting)
208 {
209     HildonSortDialogPrivate *priv;
210
211     g_return_val_if_fail (HILDON_IS_SORT_DIALOG (dialog), -1);
212
213     priv = HILDON_SORT_DIALOG_GET_PRIVATE (dialog);
214     g_assert (priv);
215
216     gboolean *new_array = g_malloc (sizeof (gboolean) * (priv->index_counter + 1));
217
218     /* Rewrite the old values */
219     int i = 0;
220     for (i = 0; i < priv->index_counter; i++) 
221         new_array [i] = priv->key_reversed [i];
222
223     new_array [priv->index_counter] = sorting;
224     gtk_combo_box_append_text (GTK_COMBO_BOX (priv->combo_key), sort_key);
225
226     /* Free the old one and reassign */
227     if (priv->key_reversed != NULL)
228         g_free (priv->key_reversed);
229     priv->key_reversed = new_array;
230
231     return priv->index_counter++;
232 }
233
234 static void 
235 reconstruct_combo                               (HildonSortDialog *dialog, 
236                                                  gboolean remove, 
237                                                  gboolean reversed)
238 {
239     HildonSortDialogPrivate *priv;
240     priv = HILDON_SORT_DIALOG_GET_PRIVATE (dialog);
241     g_assert (priv);
242
243     if (remove) {
244         gtk_combo_box_remove_text (GTK_COMBO_BOX (priv->combo_order), 1);
245         gtk_combo_box_remove_text (GTK_COMBO_BOX (priv->combo_order), 0);
246     }
247
248     if (reversed) {
249         gtk_combo_box_append_text (GTK_COMBO_BOX (priv->combo_order), _("ckdg_va_sort_descending"));
250         gtk_combo_box_append_text (GTK_COMBO_BOX (priv->combo_order), _("ckdg_va_sort_ascending"));
251     } else  {
252         gtk_combo_box_append_text (GTK_COMBO_BOX (priv->combo_order), _("ckdg_va_sort_ascending"));
253         gtk_combo_box_append_text (GTK_COMBO_BOX (priv->combo_order), _("ckdg_va_sort_descending"));
254     }
255 }
256
257 static void
258 hildon_sort_dialog_init                         (HildonSortDialog * dialog)
259 {
260     HildonSortDialogPrivate *priv;
261     GtkSizeGroup *group;
262
263     g_assert(HILDON_IS_SORT_DIALOG (dialog));
264
265     priv = HILDON_SORT_DIALOG_GET_PRIVATE (dialog);
266     g_assert (priv);
267
268     priv->index_counter = 0;
269     priv->reversed = FALSE;
270     priv->key_reversed = NULL;
271
272     group = GTK_SIZE_GROUP (gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL));
273
274     gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
275     gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
276     gtk_window_set_title (GTK_WINDOW (dialog), _("ckdg_ti_sort"));
277
278     /* Tab one */
279     priv->combo_key = gtk_combo_box_new_text ();
280     priv->caption_key = hildon_caption_new(group, _("ckdg_fi_sort_field"), priv->combo_key,
281             NULL, HILDON_CAPTION_OPTIONAL);
282     hildon_caption_set_separator(HILDON_CAPTION (priv->caption_key), "");
283     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
284             priv->caption_key, FALSE, FALSE, 0);
285
286     /* Tab two */
287     priv->combo_order = gtk_combo_box_new_text ();
288     reconstruct_combo (dialog, FALSE, FALSE);
289
290     priv->caption_order = hildon_caption_new (group, _("ckdg_fi_sort_order"),
291             priv->combo_order,
292             NULL, HILDON_CAPTION_OPTIONAL);
293     hildon_caption_set_separator(HILDON_CAPTION(priv->caption_order), "");
294     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
295             priv->caption_order, FALSE, FALSE, 0);
296
297     gtk_combo_box_set_active (GTK_COMBO_BOX (priv->combo_key), 0);
298     gtk_combo_box_set_active (GTK_COMBO_BOX (priv->combo_order), 0);
299     g_signal_connect (G_OBJECT (priv->combo_key), "changed", (gpointer) sort_key_changed, dialog);
300
301     /* Create the OK/CANCEL buttons */
302     (void) gtk_dialog_add_button (GTK_DIALOG(dialog),
303             _("ckdg_bd_sort_dialog_ok"),
304             GTK_RESPONSE_OK);
305     (void) gtk_dialog_add_button (GTK_DIALOG(dialog),
306             _("ckdg_bd_sort_dialog_cancel"),
307             GTK_RESPONSE_CANCEL);
308     /* FIXME: Hardcoded sizes are bad */
309     gtk_window_resize (GTK_WINDOW (dialog), 370, 100);
310     gtk_widget_show_all (GTK_DIALOG (dialog)->vbox);
311
312     g_object_unref (group); /* Captions now own their references to sizegroup */
313 }
314
315 /**
316  * hildon_sort_dialog_get_type:
317  *
318  * Returns GType for HildonSortDialog as produced by 
319  * g_type_register_static().
320  *
321  * Returns: HildonSortDialog type
322  */
323 GType G_GNUC_CONST
324 hildon_sort_dialog_get_type                     (void)
325 {
326     static GType dialog_type = 0;
327
328     if (!dialog_type) {
329         static const GTypeInfo dialog_info = {
330             sizeof (HildonSortDialogClass),
331             NULL,       /* base_init */
332             NULL,       /* base_finalize */
333             (GClassInitFunc) hildon_sort_dialog_class_init,
334             NULL,       /* class_finalize */
335             NULL,       /* class_data */
336             sizeof (HildonSortDialog),
337             0,  /* n_preallocs */
338             (GInstanceInitFunc) hildon_sort_dialog_init
339         };
340
341         dialog_type = g_type_register_static (GTK_TYPE_DIALOG,
342                 "HildonSortDialog",
343                 &dialog_info, 0);
344     }
345     return dialog_type;
346 }
347
348 /**
349  * hildon_sort_dialog_new:
350  * @parent: widget to be transient for, or NULL if none
351  *
352  * HildonSortDialog contains two HildonCaptions with combo boxes. 
353  *
354  * Returns: pointer to a new @HildonSortDialog widget
355  */
356 GtkWidget*
357 hildon_sort_dialog_new                          (GtkWindow * parent)
358 {
359     GtkWidget *sort_dialog = g_object_new (HILDON_TYPE_SORT_DIALOG, NULL);
360
361     if (parent)
362         gtk_window_set_transient_for (GTK_WINDOW (sort_dialog), parent);
363
364     return sort_dialog;
365 }
366
367 /**
368  * hildon_sort_dialog_get_sort_key:
369  * @dialog: the #HildonSortDialog widget
370  *
371  * Gets index to currently active sort key.
372  * 
373  * Returns: an integer which is the index value of the "Sort by" 
374  * field 
375  */
376 gint
377 hildon_sort_dialog_get_sort_key                 (HildonSortDialog *dialog)
378 {
379     GtkWidget *combo_key;
380     HildonSortDialogPrivate *priv;
381
382     g_return_val_if_fail (HILDON_IS_SORT_DIALOG (dialog), -1);
383
384     priv = HILDON_SORT_DIALOG_GET_PRIVATE (dialog);
385     g_assert (priv);
386
387     combo_key = gtk_bin_get_child (GTK_BIN (priv->caption_key));
388
389     return gtk_combo_box_get_active (GTK_COMBO_BOX (combo_key));
390 }
391
392 /**
393  * hildon_sort_dialog_get_sort_order:
394  * @dialog: the #HildonSortDialog widget
395  *
396  * Gets current sorting order from "Sort order" field.
397  *
398  * Returns: current sorting order as #GtkSortType
399  */
400 GtkSortType 
401 hildon_sort_dialog_get_sort_order               (HildonSortDialog *dialog)
402 {
403     GtkWidget *combo_order;
404     HildonSortDialogPrivate *priv;
405
406     g_return_val_if_fail (HILDON_IS_SORT_DIALOG (dialog), 0);
407
408     priv = HILDON_SORT_DIALOG_GET_PRIVATE (dialog);
409     g_assert (priv);
410
411     combo_order = gtk_bin_get_child (GTK_BIN (priv->caption_order));
412
413     gint sort_order = gtk_combo_box_get_active (GTK_COMBO_BOX (combo_order));
414
415     if (priv->reversed)
416         return (sort_order == 0) ? 1 : 0;
417     else
418         return sort_order;
419 }
420
421 /**
422  * hildon_sort_dialog_set_sort_key:
423  * @dialog: the #HildonSortDialog widget
424  * @key: combo box's index value
425  *
426  * Sets the index value of the #HildonSortDialog widget.
427  */
428 void
429 hildon_sort_dialog_set_sort_key                 (HildonSortDialog * dialog, 
430                                                  gint key)
431 {
432     GtkWidget *combo_key;
433     HildonSortDialogPrivate *priv;
434
435     g_return_if_fail (HILDON_IS_SORT_DIALOG (dialog));
436
437     priv = HILDON_SORT_DIALOG_GET_PRIVATE (dialog);
438     g_assert (priv);
439
440     combo_key = gtk_bin_get_child (GTK_BIN (priv->caption_key));
441     gtk_combo_box_set_active (GTK_COMBO_BOX (combo_key), key);
442
443     g_object_notify (G_OBJECT (dialog), "sort-key");
444 }
445
446 /**
447  * hildon_sort_dialog_set_sort_order:
448  * @dialog: the #HildonSortDialog widget
449  * @order: combo box's index value
450  *
451  * Sets the index value of the #HildonSortDialog widget.
452  */
453 void
454 hildon_sort_dialog_set_sort_order               (HildonSortDialog *dialog,
455                                                  GtkSortType order)
456 {
457     GtkWidget *combo_order;
458     HildonSortDialogPrivate *priv;
459
460     g_return_if_fail (HILDON_IS_SORT_DIALOG (dialog));
461
462     priv = HILDON_SORT_DIALOG_GET_PRIVATE (dialog);
463     g_assert (priv);
464
465     combo_order = gtk_bin_get_child (GTK_BIN (priv->caption_order));
466
467     if (priv->reversed) 
468         order = (order == 0) ? 1 : 0;
469
470     gtk_combo_box_set_active (GTK_COMBO_BOX (combo_order), order);
471
472     g_object_notify (G_OBJECT (dialog), "sort-order");
473 }
474
475 /**
476  * hildon_sort_dialog_add_sort_key:
477  * @dialog: the #HildonSortDialog widget
478  * @sort_key: combo box's index value
479  *
480  * Adds a new sort key and returns the respective index in
481  * sort key combobox.
482  *
483  * Returns: an integer which is the index of the added combo box's
484  * item
485  */
486 gint
487 hildon_sort_dialog_add_sort_key                 (HildonSortDialog *dialog,
488                                                  const gchar *sort_key)
489 {
490     return hildon_sort_dialog_add_sort_key_with_sorting (dialog, sort_key, FALSE);
491 }
492
493 /**
494  * hildon_sort_dialog_add_sort_key_reversed:
495  * @dialog: the #HildonSortDialog widget
496  * @sort_key: combo box's index value
497  *
498  * Adds a new sort key and returns the respective index in
499  * sort key combobox. The default sort order for this key is reversed (Descending first).
500  *
501  * Returns: an integer which is the index of the added combo box's
502  * item
503  *
504  */
505 gint
506 hildon_sort_dialog_add_sort_key_reversed        (HildonSortDialog *dialog,
507                                                  const gchar *sort_key)
508 {
509     return hildon_sort_dialog_add_sort_key_with_sorting (dialog, sort_key, TRUE);
510 }
511
512 static void
513 hildon_sort_dialog_set_property                 (GObject *object,
514                                                  guint prop_id,
515                                                  const GValue *value, 
516                                                  GParamSpec *pspec)
517 {
518     HildonSortDialog *dialog;
519
520     dialog = HILDON_SORT_DIALOG(object);
521
522     switch (prop_id) {
523
524         case PROP_SORT_KEY:
525             hildon_sort_dialog_set_sort_key (dialog, g_value_get_int (value));
526             break;
527
528         case PROP_SORT_ORDER:
529             hildon_sort_dialog_set_sort_order (dialog, g_value_get_enum (value));
530             break;
531
532         default:
533             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
534             break;
535     }
536 }
537
538 static void
539 hildon_sort_dialog_get_property                 (GObject *object,
540                                                  guint prop_id, 
541                                                  GValue *value, 
542                                                  GParamSpec *pspec)
543 {
544     HildonSortDialog *dialog;
545
546     dialog = HILDON_SORT_DIALOG (object);
547
548     switch (prop_id) {
549
550         case PROP_SORT_KEY:
551             g_value_set_int (value, hildon_sort_dialog_get_sort_key (dialog));
552             break;
553
554         case PROP_SORT_ORDER:
555             g_value_set_enum (value, hildon_sort_dialog_get_sort_order (dialog));
556             break;
557
558         default:
559             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
560             break;
561
562     }
563 }
564
565 static void 
566 hildon_sort_dialog_finalize                     (GObject *object)
567 {
568     HildonSortDialogPrivate *priv;
569     HildonSortDialog *dialog;
570
571     dialog = HILDON_SORT_DIALOG (object);
572     priv = HILDON_SORT_DIALOG_GET_PRIVATE (dialog);
573     g_assert (priv);
574
575     if (priv != NULL && priv->key_reversed != NULL)
576         g_free (priv->key_reversed);
577
578     if (G_OBJECT_CLASS (parent_class)->finalize)
579         G_OBJECT_CLASS (parent_class)->finalize(object);
580 }
581
582