2006-10-06 Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
[hildon] / hildon-widgets / hildon-sort-dialog.c
index 593cfd5..2c28552 100644 (file)
@@ -1,14 +1,14 @@
 /*
  * This file is part of hildon-libs
  *
- * Copyright (C) 2005 Nokia Corporation.
+ * Copyright (C) 2005, 2006 Nokia Corporation, all rights reserved.
  *
- * Contact: Luc Pionchon <luc.pionchon@nokia.com>
+ * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
+ * as published by the Free Software Foundation; version 2.1 of
+ * the License.
  *
  * This library is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  *
  */
 
-/* 
- * @file hildon-sort-dialog.c
+/** 
+ * SECTION:hildon-sort-dialog
+ * @short_description: A widget for defining the sorting order of items
  * 
- * This file contains API for Hildon Sort dialog.
- * @desc: The sort dialog is used to define the order in which item are 
- * shown in a list. Choise lists always display the current value when 
- * the dialog is opened. 
- *
+ * HildonSortDialog is used to define an order (ascending/descending)
+ * and a field by which items are sorted in a list. The combo boxes
+ * display the current value when the dialog is opened.
  */
 
 #ifdef HAVE_CONFIG_H
 
 #include <stdio.h>
 #include <libintl.h>
-
 #include <gtk/gtkcombobox.h>
 #include <gtk/gtkbox.h>
-#include <gdk/gdkkeysyms.h>
-#include <glib-object.h>
-
 #include <hildon-widgets/hildon-caption.h>
 #include "hildon-sort-dialog.h"
 
@@ -66,6 +61,15 @@ static void hildon_sort_dialog_set_property(GObject * object,
 static void hildon_sort_dialog_get_property(GObject * object,
                                      guint prop_id,
                                      GValue * value, GParamSpec * pspec);
+static void reconstruct_combo (HildonSortDialog * dialog, 
+                                     gboolean remove, 
+                                     gboolean reversed);
+static gint hildon_sort_dialog_add_sort_key_with_sorting(HildonSortDialog * dialog, 
+                                     const gchar * sort_key, 
+                                     gboolean sorting);
+static void sort_key_changed(GtkWidget * widget, 
+                             HildonSortDialog * dialog);
+static void hildon_sort_dialog_finalize(GObject * object);
 
 enum {
     PROP_0,
@@ -75,31 +79,42 @@ enum {
 
 /* private data */
 struct _HildonSortDialogPrivate {
-    /* Tab one */
-    GtkWidget *combo1;
-    GtkWidget *caption1;
-
-    /* Tab two */
-    GtkWidget *combo2;
-    GtkWidget *caption2;
-
-    /* OK/Cancel buttons */
-    GtkWidget *okButton;
-    GtkWidget *cancelButton;
-
-    /* Index value for sort_by */
-    gint sort_by_value;
+    /* Sort category widgets */
+    GtkWidget *combo_key;
+    GtkWidget *caption_key;
 
-    /* Index value for sort_order */
-    gint sort_order_type;
+    /* Sort order widgets */
+    GtkWidget *combo_order;
+    GtkWidget *caption_order;
 
-    gboolean index_first;
     /* Index value counter */
     gint index_counter;
+
+    /* If the current order displayed is reversed */
+    gboolean reversed;
+
+    /* An array for each key representing if a key should be reverse-sorted */
+    gboolean *key_reversed;
 };
 
 /* Private functions */
 
+static void sort_key_changed(GtkWidget * widget, HildonSortDialog * dialog)
+{
+    g_return_if_fail(HILDON_IS_SORT_DIALOG(dialog));
+
+    HildonSortDialogPrivate *priv = HILDON_SORT_DIALOG_GET_PRIVATE(dialog);
+
+    gint index = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
+
+    if (priv->key_reversed [index] != priv->reversed) {
+        reconstruct_combo (dialog, TRUE, priv->key_reversed [index]);
+        gtk_combo_box_set_active(GTK_COMBO_BOX(priv->combo_order), 0);
+    }
+
+    priv->reversed = priv->key_reversed [index];
+}
+
 /*
  * Initialises the sort dialog class.
  */
@@ -111,6 +126,7 @@ static void hildon_sort_dialog_class_init(HildonSortDialogClass * class)
     
     gobject_class->set_property = hildon_sort_dialog_set_property;
     gobject_class->get_property = hildon_sort_dialog_get_property;
+    gobject_class->finalize = (gpointer) hildon_sort_dialog_finalize;
     
     g_object_class_install_property(gobject_class, PROP_SORT_KEY,
         g_param_spec_int("sort-key",
@@ -129,17 +145,62 @@ static void hildon_sort_dialog_class_init(HildonSortDialogClass * class)
                         G_PARAM_READWRITE));
 }
 
+static gint hildon_sort_dialog_add_sort_key_with_sorting(HildonSortDialog * dialog, const gchar * sort_key, gboolean sorting)
+{
+    HildonSortDialogPrivate *priv;
+
+    g_return_val_if_fail(HILDON_IS_SORT_DIALOG(dialog), -1);
+
+    priv = HILDON_SORT_DIALOG_GET_PRIVATE(dialog);
+    gboolean *new_array = g_malloc (sizeof (gboolean) * (priv->index_counter + 1));
+
+    /* Rewrite the old values */
+    int i = 0;
+    for (i = 0; i < priv->index_counter; i++) 
+        new_array [i] = priv->key_reversed [i];
+
+    new_array [priv->index_counter] = sorting;
+    gtk_combo_box_append_text(GTK_COMBO_BOX(priv->combo_key), sort_key);
+
+    /* Free the old one and reassign */
+    if (priv->key_reversed != NULL)
+        g_free (priv->key_reversed);
+    priv->key_reversed = new_array;
+
+    return priv->index_counter++;
+}
+
+static void reconstruct_combo (HildonSortDialog * dialog, gboolean remove, gboolean reversed)
+{
+    HildonSortDialogPrivate *priv;
+    priv = HILDON_SORT_DIALOG_GET_PRIVATE(dialog);
+
+    if (remove) {
+        gtk_combo_box_remove_text(GTK_COMBO_BOX(priv->combo_order), 1);
+        gtk_combo_box_remove_text(GTK_COMBO_BOX(priv->combo_order), 0);
+    }
+
+    if (reversed) {
+        gtk_combo_box_append_text(GTK_COMBO_BOX(priv->combo_order), _("ckdg_va_sort_descending"));
+        gtk_combo_box_append_text(GTK_COMBO_BOX(priv->combo_order), _("ckdg_va_sort_ascending"));
+    } else {
+        gtk_combo_box_append_text(GTK_COMBO_BOX(priv->combo_order), _("ckdg_va_sort_ascending"));
+        gtk_combo_box_append_text(GTK_COMBO_BOX(priv->combo_order), _("ckdg_va_sort_descending"));
+    }
+}
+
 static void hildon_sort_dialog_init(HildonSortDialog * dialog)
 {
     HildonSortDialogPrivate *priv;
     GtkSizeGroup *group;
 
-    g_return_if_fail(HILDON_IS_SORT_DIALOG(dialog));
+    g_assert(HILDON_IS_SORT_DIALOG(dialog));
 
     priv = HILDON_SORT_DIALOG_GET_PRIVATE(dialog);
 
-    priv->index_first = TRUE;
     priv->index_counter = 0;
+    priv->reversed = FALSE;
+    priv->key_reversed = NULL;
 
     group = GTK_SIZE_GROUP(gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL));
 
@@ -148,40 +209,40 @@ static void hildon_sort_dialog_init(HildonSortDialog * dialog)
     gtk_window_set_title(GTK_WINDOW(dialog), _("ckdg_ti_sort"));
 
     /* Tab one */
-    priv->combo1 = gtk_combo_box_new_text();
-    priv->caption1 = hildon_caption_new(group, _("ckdg_fi_sort_field"), priv->combo1,
+    priv->combo_key = gtk_combo_box_new_text();
+    priv->caption_key = hildon_caption_new(group, _("ckdg_fi_sort_field"), priv->combo_key,
                                         NULL, HILDON_CAPTION_OPTIONAL);
-    hildon_caption_set_separator(HILDON_CAPTION(priv->caption1), "");
+    hildon_caption_set_separator(HILDON_CAPTION(priv->caption_key), "");
     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
-                       priv->caption1, FALSE, FALSE, 0);
+                       priv->caption_key, FALSE, FALSE, 0);
 
     /* Tab two */
-    priv->combo2 = gtk_combo_box_new_text();
-    gtk_combo_box_append_text(GTK_COMBO_BOX(priv->combo2),
-                              _("ckdg_va_sort_ascending"));
-    gtk_combo_box_append_text(GTK_COMBO_BOX(priv->combo2),
-                              _("ckdg_va_sort_descending"));
-
-    priv->caption2 = hildon_caption_new(group, _("ckdg_fi_sort_order"),
-                                        priv->combo2,
+    priv->combo_order = gtk_combo_box_new_text();
+    reconstruct_combo (dialog, FALSE, FALSE);
+    
+    priv->caption_order = hildon_caption_new(group, _("ckdg_fi_sort_order"),
+                                        priv->combo_order,
                                         NULL, HILDON_CAPTION_OPTIONAL);
-    hildon_caption_set_separator(HILDON_CAPTION(priv->caption2), "");
+    hildon_caption_set_separator(HILDON_CAPTION(priv->caption_order), "");
     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
-                       priv->caption2, FALSE, FALSE, 0);
+                       priv->caption_order, FALSE, FALSE, 0);
 
-    gtk_combo_box_set_active(GTK_COMBO_BOX(priv->combo1), 0);
-    gtk_combo_box_set_active(GTK_COMBO_BOX(priv->combo2), 0);
+    gtk_combo_box_set_active(GTK_COMBO_BOX(priv->combo_key), 0);
+    gtk_combo_box_set_active(GTK_COMBO_BOX(priv->combo_order), 0);
+    g_signal_connect (G_OBJECT (priv->combo_key), "changed", (gpointer) sort_key_changed, dialog);
 
     /* Create the OK/CANCEL buttons */
-    priv->okButton = gtk_dialog_add_button(GTK_DIALOG(dialog),
+    (void) gtk_dialog_add_button(GTK_DIALOG(dialog),
                                            _("ckdg_bd_sort_dialog_ok"),
                                            GTK_RESPONSE_OK);
-    priv->cancelButton = gtk_dialog_add_button(GTK_DIALOG(dialog),
+    (void) gtk_dialog_add_button(GTK_DIALOG(dialog),
                                                _("ckdg_bd_sort_dialog_cancel"),
                                                GTK_RESPONSE_CANCEL);
-
+    /* FIXME: Hardcoded sizes are bad */
     gtk_window_resize(GTK_WINDOW(dialog), 370, 100);
     gtk_widget_show_all(GTK_DIALOG(dialog)->vbox);
+
+    g_object_unref(group); /* Captions now own their references to sizegroup */
 }
 
 /* Public functions */
@@ -192,8 +253,8 @@ static void hildon_sort_dialog_init(HildonSortDialog * dialog)
  * Returns GType for HildonSortDialog as produced by 
  * g_type_register_static().
  *
- * Return value: HildonSortDialog type
- **/
+ * Returns: HildonSortDialog type
+ */
 GType hildon_sort_dialog_get_type()
 {
     static GType dialog_type = 0;
@@ -220,11 +281,11 @@ GType hildon_sort_dialog_get_type()
 
 /**
  * hildon_sort_dialog_new:
- * @parent: Widget to be transient for, or NULL if none.
+ * @parent: widget to be transient for, or NULL if none
  *
- * HildonSortDialog contains two #HildonCaption:s with combo boxes. 
+ * HildonSortDialog contains two HildonCaptions with combo boxes. 
  *
- * Return value: pointer to a new @HildonSortDialog widget.
+ * Returns: pointer to a new @HildonSortDialog widget
  */
 GtkWidget *hildon_sort_dialog_new(GtkWindow * parent)
 {
@@ -238,11 +299,11 @@ GtkWidget *hildon_sort_dialog_new(GtkWindow * parent)
 
 /**
  * hildon_sort_dialog_get_sort_key:
- * @dialog: the #HildonSortDialog widget.
+ * @dialog: the #HildonSortDialog widget
  *
  * Gets index to currently active sort key.
  * 
- * Return value: An integer which is the index value of the "Sort by" 
+ * Returns: an integer which is the index value of the "Sort by" 
  * field 
  */
 gint hildon_sort_dialog_get_sort_key(HildonSortDialog * dialog)
@@ -254,38 +315,41 @@ gint hildon_sort_dialog_get_sort_key(HildonSortDialog * dialog)
 
     priv = HILDON_SORT_DIALOG_GET_PRIVATE(dialog);
     
-    combo_key = gtk_bin_get_child(GTK_BIN(priv->caption1));
-    priv->sort_by_value =
-        gtk_combo_box_get_active(GTK_COMBO_BOX(combo_key));
-    return priv->sort_by_value;
+    combo_key = gtk_bin_get_child(GTK_BIN(priv->caption_key));
+
+    return gtk_combo_box_get_active(GTK_COMBO_BOX(combo_key));
 }
 
 /**
  * hildon_sort_dialog_get_sort_order:
- * @dialog: the #HildonSortDialog widget.
+ * @dialog: the #HildonSortDialog widget
  *
  * Gets current sorting order from "Sort order" field.
  *
- * Return value: current sorting order as #GtkSortType.
+ * Returns: current sorting order as #GtkSortType
  */
 GtkSortType hildon_sort_dialog_get_sort_order(HildonSortDialog * dialog)
 {
-    GtkWidget *combo_key;
+    GtkWidget *combo_order;
     HildonSortDialogPrivate *priv;
 
     g_return_val_if_fail(HILDON_IS_SORT_DIALOG(dialog), 0);
 
     priv = HILDON_SORT_DIALOG_GET_PRIVATE(dialog);
-    combo_key = gtk_bin_get_child(GTK_BIN(priv->caption2));
-    priv->sort_order_type =
-        gtk_combo_box_get_active(GTK_COMBO_BOX(combo_key));
-    return priv->sort_order_type;
+    combo_order = gtk_bin_get_child(GTK_BIN(priv->caption_order));
+
+    gint sort_order = gtk_combo_box_get_active(GTK_COMBO_BOX(combo_order));
+
+    if (priv->reversed)
+        return (sort_order == 0) ? 1 : 0;
+    else
+        return sort_order;
 }
 
 /**
  * hildon_sort_dialog_set_sort_key:
- * @dialog: the #HildonSortDialog widget.
- * @key: Combo box's index value.
+ * @dialog: the #HildonSortDialog widget
+ * @key: combo box's index value
  *
  * Sets the index value of the #HildonSortDialog widget.
  */
@@ -297,7 +361,7 @@ void hildon_sort_dialog_set_sort_key(HildonSortDialog * dialog, gint key)
     g_return_if_fail(HILDON_IS_SORT_DIALOG(dialog));
 
     priv = HILDON_SORT_DIALOG_GET_PRIVATE(dialog);
-    combo_key = gtk_bin_get_child(GTK_BIN(priv->caption1));
+    combo_key = gtk_bin_get_child(GTK_BIN(priv->caption_key));
     gtk_combo_box_set_active(GTK_COMBO_BOX(combo_key), key);
 
     g_object_notify (G_OBJECT (dialog), "sort-key");
@@ -305,8 +369,8 @@ void hildon_sort_dialog_set_sort_key(HildonSortDialog * dialog, gint key)
 
 /**
  * hildon_sort_dialog_set_sort_order:
- * @dialog: the #HildonSortDialog widget.
- * @order: Combo box's index value.
+ * @dialog: the #HildonSortDialog widget
+ * @order: combo box's index value
  *
  * Sets the index value of the #HildonSortDialog widget.
  */
@@ -320,7 +384,11 @@ hildon_sort_dialog_set_sort_order(HildonSortDialog * dialog,
     g_return_if_fail(HILDON_IS_SORT_DIALOG(dialog));
 
     priv = HILDON_SORT_DIALOG_GET_PRIVATE(dialog);
-    combo_order = gtk_bin_get_child(GTK_BIN(priv->caption2));
+    combo_order = gtk_bin_get_child(GTK_BIN(priv->caption_order));
+    
+    if (priv->reversed) 
+        order = (order == 0) ? 1 : 0;
+    
     gtk_combo_box_set_active(GTK_COMBO_BOX(combo_order), order);
 
     g_object_notify (G_OBJECT (dialog), "sort-order");
@@ -328,33 +396,40 @@ hildon_sort_dialog_set_sort_order(HildonSortDialog * dialog,
 
 /**
  * hildon_sort_dialog_add_sort_key:
- * @dialog: the #HildonSortDialog widget.
- * @sort_key: Combo box's index value
+ * @dialog: the #HildonSortDialog widget
+ * @sort_key: combo box's index value
  *
  * Adds a new sort key and returns the respective index in
  * sort key combobox.
  *
- * Return value: An integer which is the index of the added combo box's
- * item.
+ * Returns: an integer which is the index of the added combo box's
+ * item
  */
 gint
 hildon_sort_dialog_add_sort_key(HildonSortDialog * dialog,
                                 const gchar * sort_key)
 {
-    HildonSortDialogPrivate *priv;
-
-    g_return_val_if_fail(HILDON_IS_SORT_DIALOG(dialog), -1);
-
-    priv = HILDON_SORT_DIALOG_GET_PRIVATE(dialog);
-    gtk_combo_box_append_text(GTK_COMBO_BOX(priv->combo1), sort_key);
-
-    if (priv->index_first == TRUE) {
-        priv->index_first = FALSE;
-        return priv->index_counter;
+    return hildon_sort_dialog_add_sort_key_with_sorting (dialog, sort_key, FALSE);
+}
 
-    } else {
-        return priv->index_counter += 1;
-    }
+/**
+ * hildon_sort_dialog_add_sort_key_reversed:
+ * @dialog: the #HildonSortDialog widget
+ * @sort_key: combo box's index value
+ *
+ * Adds a new sort key and returns the respective index in
+ * sort key combobox. The default sort order for this key is reversed (Descending first).
+ *
+ * Returns: an integer which is the index of the added combo box's
+ * item
+ *
+ * Since: 0.14.1
+ */
+gint
+hildon_sort_dialog_add_sort_key_reversed(HildonSortDialog * dialog,
+                                const gchar * sort_key)
+{
+    return hildon_sort_dialog_add_sort_key_with_sorting (dialog, sort_key, TRUE);
 }
 
 static void
@@ -400,3 +475,21 @@ hildon_sort_dialog_get_property(GObject * object,
     }
 }
 
+static void 
+hildon_sort_dialog_finalize(GObject * object)
+{
+    HildonSortDialogPrivate *priv;
+    HildonSortDialog *dialog;
+
+    g_return_if_fail (HILDON_IS_SORT_DIALOG (object));
+    dialog = HILDON_SORT_DIALOG(object);
+
+    priv = HILDON_SORT_DIALOG_GET_PRIVATE(dialog);
+    if (priv != NULL && priv->key_reversed != NULL)
+        g_free(priv->key_reversed);
+
+    if (G_OBJECT_CLASS(parent_class)->finalize)
+        G_OBJECT_CLASS(parent_class)->finalize(object);
+}
+
+