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