* SECTION:hildon-picker-dialog
* @short_description: A utility widget that shows a #HildonTouchSelector widget
*
- * HildonPickerDialog is a utility widget that shows a #HildonTouchSelector widget in
- * a new dialog (see #GtkDialog for more information about this issue)
+ * #HildonPickerDialog is a dialog that is used to show a
+ * #HildonTouchSelector widget and a 'Done' button to allow users to
+ * finish their selections.
*
+ * The #HildonPickerDialog will show a 'Done' button in case the
+ * #HildonTouchSelector allows multiple selection. The label of the
+ * button can be set using hildon_picker_dialog_set_done_label() and
+ * retrieved using hildon_picker_dialog_get_done_label()
+ *
+ * Note that in most cases developers don't need to deal directly with
+ * this widget. #HildonPickerButton is designed to pop up a
+ * #HildonPickerDialog and manage the interaction with it.
*/
#ifdef HAVE_CONFIG_H
#include <string.h>
#include <stdlib.h>
-
#include <libintl.h>
-#include <gtk/gtkmarshal.h>
#include "hildon-touch-selector.h"
+#include "hildon-touch-selector-entry.h"
#include "hildon-picker-dialog.h"
#define _(String) dgettext("hildon-libs", String)
#define HILDON_PICKER_DIALOG_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), HILDON_TYPE_PICKER_DIALOG, HildonPickerDialogPrivate))
-G_DEFINE_TYPE (HildonPickerDialog, hildon_picker_dialog, GTK_TYPE_DIALOG)
+G_DEFINE_TYPE (HildonPickerDialog, hildon_picker_dialog, HILDON_TYPE_DIALOG)
+
+#define HILDON_TOUCH_SELECTOR_HEIGHT 320
struct _HildonPickerDialogPrivate
{
GtkWidget *selector;
- GtkWidget *separator;
GtkWidget *button;
- GtkWidget *title_label;
+ gulong signal_changed_id;
+ gulong signal_columns_changed_id;
- gulong signal_id;
+ gboolean center_on_show;
+ GSList *current_selection;
+ gchar *current_text;
};
/* properties */
{
PROP_0,
PROP_DONE_BUTTON_TEXT,
+ PROP_CENTER_ON_SHOW,
PROP_LAST
};
LAST_SIGNAL
};
-#define DEFAULT_DONE_BUTTON_TEXT "Done"
+#define DEFAULT_DONE_BUTTON_TEXT _("wdgt_bd_done")
static void
-hildon_picker_dialog_set_property (GObject * object,
- guint prop_id,
- const GValue * value,
- GParamSpec * pspec);
+hildon_picker_dialog_set_property (GObject * object,
+ guint prop_id,
+ const GValue * value,
+ GParamSpec * pspec);
static void
-hildon_picker_dialog_get_property (GObject * object,
- guint prop_id,
- GValue * value, GParamSpec * pspec);
+hildon_picker_dialog_get_property (GObject * object,
+ guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void
+hildon_picker_dialog_finalize (GObject *object);
+
/* gtkwidget */
-static void hildon_picker_dialog_realize (GtkWidget * widget);
+static void
+hildon_picker_dialog_show (GtkWidget *widget);
+
+static void
+hildon_picker_dialog_realize (GtkWidget *widget);
/* private functions */
-static gboolean requires_done_button (HildonPickerDialog * dialog);
+static gboolean
+requires_done_button (HildonPickerDialog * dialog);
+
+static void
+prepare_action_area (HildonPickerDialog *dialog);
+
+static void
+setup_interaction_mode (HildonPickerDialog * dialog);
static void
-_select_on_selector_changed_cb (HildonTouchSelector * dialog,
- gint column, gpointer data);
+_select_on_selector_changed_cb (HildonTouchSelector * dialog,
+ gint column,
+ gpointer data);
static gboolean
-_hildon_picker_dialog_set_selector (HildonPickerDialog * dialog,
- HildonTouchSelector * selector);
+_hildon_picker_dialog_set_selector (HildonPickerDialog * dialog,
+ HildonTouchSelector * selector);
static void
-_update_title_on_selector_changed_cb (HildonTouchSelector * selector,
- gint column, gpointer data);
+_on_dialog_response (GtkDialog *dialog,
+ gint response_id,
+ gpointer data);
+
+static void
+_save_current_selection (HildonPickerDialog *dialog);
+
+static void
+_restore_current_selection (HildonPickerDialog *dialog);
+
+static void
+_clean_current_selection (HildonPickerDialog *dialog);
+
+/**********************************************************************************/
static void
hildon_picker_dialog_class_init (HildonPickerDialogClass * class)
/* GObject */
gobject_class->set_property = hildon_picker_dialog_set_property;
gobject_class->get_property = hildon_picker_dialog_get_property;
+ gobject_class->finalize = hildon_picker_dialog_finalize;
/* GtkWidget */
+ widget_class->show = hildon_picker_dialog_show;
widget_class->realize = hildon_picker_dialog_realize;
/* HildonPickerDialog */
* HildonPickerDialog
*
* Button label
+ *
+ * Since: 2.2
*/
g_object_class_install_property (gobject_class,
PROP_DONE_BUTTON_TEXT,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT));
+ g_object_class_install_property (gobject_class,
+ PROP_CENTER_ON_SHOW,
+ g_param_spec_boolean ("center-on-show",
+ "Center on show",
+ "If the dialog should center"
+ " on the current selection"
+ " when it is showed",
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
g_type_class_add_private (object_class, sizeof (HildonPickerDialogPrivate));
}
static void
hildon_picker_dialog_init (HildonPickerDialog * dialog)
{
- GtkWidget *separator = NULL;
-
dialog->priv = HILDON_PICKER_DIALOG_GET_PRIVATE (dialog);
dialog->priv->selector = NULL;
gtk_dialog_add_button (GTK_DIALOG (dialog), "", GTK_RESPONSE_OK);
gtk_widget_grab_default (dialog->priv->button);
- dialog->priv->title_label = gtk_label_new ("default value");
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
- dialog->priv->title_label, FALSE, FALSE, 0);
- separator = gtk_hseparator_new ();
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
- separator, FALSE, FALSE, 0);
+ dialog->priv->signal_changed_id = 0;
+ dialog->priv->signal_columns_changed_id = 0;
+ dialog->priv->center_on_show = TRUE;
+ dialog->priv->current_selection = NULL;
+ dialog->priv->current_text = NULL;
- dialog->priv->signal_id = 0;
-
-/* gtk_widget_show (dialog->priv->title_label); */
-/* gtk_widget_show (separator); */
+ g_signal_connect (G_OBJECT (dialog),
+ "response", G_CALLBACK (_on_dialog_response),
+ NULL);
}
guint param_id,
const GValue * value, GParamSpec * pspec)
{
- HildonPickerDialogPrivate *priv = HILDON_PICKER_DIALOG_GET_PRIVATE (object);
- g_assert (priv);
+ HildonPickerDialog *dialog;
+
+ dialog = HILDON_PICKER_DIALOG (object);
switch (param_id) {
case PROP_DONE_BUTTON_TEXT:
hildon_picker_dialog_set_done_label (HILDON_PICKER_DIALOG (object),
g_value_get_string (value));
break;
+ case PROP_CENTER_ON_SHOW:
+ dialog->priv->center_on_show = g_value_get_boolean (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
GValue * value, GParamSpec * pspec)
{
HildonPickerDialog *dialog;
- HildonPickerDialogPrivate *priv;
dialog = HILDON_PICKER_DIALOG (object);
- priv = HILDON_PICKER_DIALOG_GET_PRIVATE (object);
switch (param_id) {
case PROP_DONE_BUTTON_TEXT:
g_value_set_string (value, hildon_picker_dialog_get_done_label (dialog));
break;
+ case PROP_CENTER_ON_SHOW:
+ g_value_set_boolean (value, dialog->priv->center_on_show);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
-
static void
-hildon_picker_dialog_realize (GtkWidget * widget)
+hildon_picker_dialog_finalize (GObject *object)
{
- GTK_WIDGET_CLASS (hildon_picker_dialog_parent_class)->realize (widget);
+ _clean_current_selection (HILDON_PICKER_DIALOG (object));
-/* gdk_window_set_decorations (widget->window, GDK_DECOR_BORDER); */
+ G_OBJECT_CLASS (hildon_picker_dialog_parent_class)->finalize (object);
}
-/* ------------------------------ PRIVATE METHODS ---------------------------- */
static void
-_select_on_selector_changed_cb (HildonTouchSelector * selector,
- gint column, gpointer data)
+hildon_picker_dialog_show (GtkWidget *widget)
{
- HildonPickerDialog *dialog = NULL;
+ HildonPickerDialog *dialog = HILDON_PICKER_DIALOG (widget);
+ HildonTouchSelector *selector;
- g_return_if_fail (HILDON_IS_PICKER_DIALOG (data));
+ if (dialog->priv->center_on_show) {
+ selector = hildon_picker_dialog_get_selector (dialog);
+ hildon_touch_selector_center_on_selected (selector);
+ }
- dialog = HILDON_PICKER_DIALOG (data);
+ _save_current_selection (dialog);
+ prepare_action_area (dialog);
- gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+ GTK_WIDGET_CLASS (hildon_picker_dialog_parent_class)->show (widget);
}
static void
-_update_title_on_selector_changed_cb (HildonTouchSelector * selector,
- gint column, gpointer data)
+hildon_picker_dialog_realize (GtkWidget *widget)
{
- HildonPickerDialog *dialog = NULL;
- gchar *new_title = NULL;
+ setup_interaction_mode (HILDON_PICKER_DIALOG (widget));
+
+ GTK_WIDGET_CLASS (hildon_picker_dialog_parent_class)->realize (widget);
+}
+
+/* ------------------------------ PRIVATE METHODS ---------------------------- */
+static void
+_select_on_selector_changed_cb (HildonTouchSelector * selector,
+ gint column, gpointer data)
+{
g_return_if_fail (HILDON_IS_PICKER_DIALOG (data));
- dialog = HILDON_PICKER_DIALOG (data);
+ gtk_dialog_response (GTK_DIALOG (data), GTK_RESPONSE_OK);
+}
+
+static gboolean
+selection_completed (HildonPickerDialog *dialog)
+{
+ HildonPickerDialogPrivate *priv;
+ GList *list;
+ gint i, n_cols;
+ gboolean all_selected = TRUE;
- new_title = hildon_touch_selector_get_current_text (selector);
+ priv = HILDON_PICKER_DIALOG_GET_PRIVATE (dialog);
- if (dialog->priv->title_label != NULL) {
-/* gtk_label_set_text (GTK_LABEL(selector->priv->title_label), new_title); */
+ n_cols = hildon_touch_selector_get_num_columns (HILDON_TOUCH_SELECTOR (priv->selector));
+ for (i = 0; i < n_cols; i++) {
+ list = hildon_touch_selector_get_selected_rows (HILDON_TOUCH_SELECTOR (priv->selector), i);
+ if (list == NULL) {
+ all_selected = FALSE;
+ break;
+ }
+ g_list_foreach (list, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free (list);
}
- gtk_window_set_title (GTK_WINDOW (dialog), new_title);
- g_free (new_title);
+ return all_selected;
}
+static void
+_on_dialog_response (GtkDialog *dialog,
+ gint response_id,
+ gpointer data)
+{
+ if (response_id == GTK_RESPONSE_OK) {
+ if (selection_completed (HILDON_PICKER_DIALOG (dialog)) == FALSE) {
+ g_signal_stop_emission_by_name (dialog, "response");
+ }
+ } else if (response_id == GTK_RESPONSE_DELETE_EVENT) {
+ _restore_current_selection (HILDON_PICKER_DIALOG (dialog));
+ }
+}
+
+static void
+on_selector_columns_changed (HildonTouchSelector * selector, gpointer userdata)
+{
+ HildonPickerDialog * dialog;
+
+ dialog = HILDON_PICKER_DIALOG (userdata);
+ prepare_action_area (dialog);
+ if (GTK_WIDGET_REALIZED (dialog)) {
+ setup_interaction_mode (dialog);
+ }
+}
+
+/**
+ * hildon_picker_dialog_set_done_label:
+ * @dialog: a #HildonPickerDialog
+ * @label: a string
+ *
+ * Sets a custom string to be used as the 'Done' button label in @dialog.
+ *
+ * Since: 2.2
+ **/
void
hildon_picker_dialog_set_done_label (HildonPickerDialog * dialog,
const gchar * label)
gtk_button_set_label (GTK_BUTTON (priv->button), label);
}
+/**
+ * hildon_picker_dialog_get_done_label:
+ * @dialog: a #HildonPickerDialog
+ *
+ * Retrieves current 'Done' button label.
+ *
+ * Returns: the custom string to be used.
+ *
+ * Since: 2.2
+ **/
const gchar *
hildon_picker_dialog_get_done_label (HildonPickerDialog * dialog)
{
return gtk_button_get_label (GTK_BUTTON (priv->button));
}
+static void
+free_path_list (GList *list)
+{
+ g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (list);
+}
+
+static void
+_clean_current_selection (HildonPickerDialog *dialog)
+{
+ if (dialog->priv->current_selection) {
+ g_slist_foreach (dialog->priv->current_selection, (GFunc) free_path_list, NULL);
+ g_slist_free (dialog->priv->current_selection);
+ dialog->priv->current_selection = NULL;
+ }
+ if (dialog->priv->current_text) {
+ g_free (dialog->priv->current_text);
+ dialog->priv->current_text = NULL;
+ }
+}
+
+static void
+_save_current_selection (HildonPickerDialog *dialog)
+{
+ HildonTouchSelector *selector;
+ gint i, columns;
+
+ selector = HILDON_TOUCH_SELECTOR (dialog->priv->selector);
+
+ _clean_current_selection (dialog);
+
+ columns = hildon_touch_selector_get_num_columns (selector);
+ for (i = 0; i < columns; i++) {
+ dialog->priv->current_selection
+ = g_slist_append (dialog->priv->current_selection,
+ hildon_touch_selector_get_selected_rows (selector, i));
+ }
+ if (HILDON_IS_TOUCH_SELECTOR_ENTRY (selector)) {
+ HildonEntry *entry = hildon_touch_selector_entry_get_entry (HILDON_TOUCH_SELECTOR_ENTRY (selector));
+ dialog->priv->current_text = g_strdup (hildon_entry_get_text (entry));
+ }
+}
+
+static void
+_restore_current_selection (HildonPickerDialog *dialog)
+{
+ GSList *current_selection, *iter;
+ GList *selected, *selected_iter;
+ GtkTreePath *current_path;
+ HildonTouchSelector *selector;
+ GtkTreeModel *model;
+ GtkTreeIter tree_iter;
+ gint i;
+
+ if (dialog->priv->current_selection == NULL)
+ return;
+
+ current_selection = dialog->priv->current_selection;
+ selector = HILDON_TOUCH_SELECTOR (dialog->priv->selector);
+
+ if (hildon_touch_selector_get_num_columns (selector) !=
+ g_slist_length (current_selection)) {
+ /* We conclude that if the current selection has the same
+ numbers of columns that the selector, all this ok
+ Anyway this shouldn't happen. */
+ g_critical ("Trying to restore the selection on a selector after change"
+ " the number of columns. Are you removing columns while the"
+ " dialog is open?");
+ return;
+ }
+
+ if (dialog->priv->signal_changed_id)
+ g_signal_handler_block (selector, dialog->priv->signal_changed_id);
+ for (iter = current_selection, i = 0; iter; iter = g_slist_next (iter), i++) {
+ selected = (GList *) (iter->data);
+ model = hildon_touch_selector_get_model (selector, i);
+ hildon_touch_selector_unselect_all (selector, i);
+ for (selected_iter = selected; selected_iter; selected_iter = g_list_next (selected_iter)) {
+ current_path = (GtkTreePath *) selected_iter->data;
+ gtk_tree_model_get_iter (model, &tree_iter, current_path);
+ hildon_touch_selector_select_iter (selector, i, &tree_iter, FALSE);
+ }
+ }
+ if (HILDON_IS_TOUCH_SELECTOR_ENTRY (selector) && dialog->priv->current_text != NULL) {
+ HildonEntry *entry = hildon_touch_selector_entry_get_entry (HILDON_TOUCH_SELECTOR_ENTRY (selector));
+ hildon_entry_set_text (entry, dialog->priv->current_text);
+ }
+ if (dialog->priv->signal_changed_id)
+ g_signal_handler_unblock (selector, dialog->priv->signal_changed_id);
+}
+
static gboolean
requires_done_button (HildonPickerDialog * dialog)
{
(HILDON_TOUCH_SELECTOR (dialog->priv->selector));
}
-/* ------------------------------ PUBLIC METHODS ---------------------------- */
+static void
+prepare_action_area (HildonPickerDialog *dialog)
+{
+ if (requires_done_button (dialog)) {
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), TRUE);
+ gtk_widget_show (GTK_DIALOG (dialog)->action_area);
+ } else {
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+ gtk_widget_hide (GTK_DIALOG (dialog)->action_area);
+ }
+}
+
+static void
+setup_interaction_mode (HildonPickerDialog * dialog)
+{
+ if (dialog->priv->signal_changed_id) {
+ g_signal_handler_disconnect (dialog->priv->selector,
+ dialog->priv->signal_changed_id);
+ }
+
+ if (requires_done_button (dialog) == FALSE) {
+ dialog->priv->signal_changed_id =
+ g_signal_connect (G_OBJECT (dialog->priv->selector), "changed",
+ G_CALLBACK (_select_on_selector_changed_cb), dialog);
+ }
+}
+
+/*------------------------- PUBLIC METHODS ---------------------------- */
/**
* hildon_picker_dialog_new:
* Creates a new #HildonPickerDialog
*
* Returns: a new #HildonPickerDialog
+ *
+ * Since: 2.2
**/
GtkWidget *
hildon_picker_dialog_new (GtkWindow * parent)
_hildon_picker_dialog_set_selector (HildonPickerDialog * dialog,
HildonTouchSelector * selector)
{
+ g_object_ref (selector);
+
+ /* Remove the old selector, if any */
if (dialog->priv->selector != NULL) {
gtk_container_remove (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox),
dialog->priv->selector);
- g_object_unref (dialog->priv->selector);
- dialog->priv->selector = NULL;
+ if (dialog->priv->signal_columns_changed_id) {
+ g_signal_handler_disconnect (dialog->priv->selector,
+ dialog->priv->signal_columns_changed_id);
+ }
}
dialog->priv->selector = GTK_WIDGET (selector);
- if (dialog->priv->selector != NULL) {
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
- dialog->priv->selector, TRUE, TRUE, 0);
- gtk_widget_show (dialog->priv->selector);
- g_object_ref (dialog->priv->selector);
- }
+ /* Pack the new selector */
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+ dialog->priv->selector, TRUE, TRUE, 0);
- if (dialog->priv->signal_id) {
- g_signal_handler_disconnect (dialog->priv->selector,
- dialog->priv->signal_id);
- }
+ g_object_unref (selector);
- if (requires_done_button (dialog)) {
- gtk_dialog_set_has_separator (GTK_DIALOG (dialog), TRUE);
- gtk_widget_show (GTK_DIALOG (dialog)->action_area);
- /* update the title */
- dialog->priv->signal_id =
- g_signal_connect (G_OBJECT (dialog->priv->selector), "changed",
- G_CALLBACK (_update_title_on_selector_changed_cb),
- dialog);
- } else {
- gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
- gtk_widget_hide (GTK_DIALOG (dialog)->action_area);
- dialog->priv->signal_id =
- g_signal_connect (G_OBJECT (dialog->priv->selector), "changed",
- G_CALLBACK (_select_on_selector_changed_cb), dialog);
+ /* Ensure that the dialog's height is correct */
+ gtk_widget_set_size_request (GTK_WIDGET (dialog->priv->selector), -1,
+ HILDON_TOUCH_SELECTOR_HEIGHT);
+
+ gtk_widget_show (dialog->priv->selector);
+
+ prepare_action_area (dialog);
+ if (GTK_WIDGET_REALIZED (dialog)) {
+ setup_interaction_mode (dialog);
}
+ dialog->priv->signal_columns_changed_id = g_signal_connect (G_OBJECT (dialog->priv->selector),
+ "columns-changed",
+ G_CALLBACK (on_selector_columns_changed), dialog);
return TRUE;
}
+/**
+ * hildon_picker_dialog_set_selector:
+ * @dialog: a #HildonPickerDialog
+ * @selector: a #HildonTouchSelector
+ *
+ * Sets @selector as the #HildonTouchSelector to be shown in @dialog
+ *
+ * Returns: %TRUE if @selector was set, %FALSE otherwise
+ *
+ * Since: 2.2
+ **/
gboolean
hildon_picker_dialog_set_selector (HildonPickerDialog * dialog,
HildonTouchSelector * selector)
return HILDON_PICKER_DIALOG_GET_CLASS (dialog)->set_selector (dialog, selector);
}
+/**
+ * hildon_picker_dialog_get_selector:
+ * @dialog: a #HildonPickerDialog
+ *
+ * Retrieves the #HildonTouchSelector associated to @dialog.
+ *
+ * Returns: a #HildonTouchSelector
+ *
+ * Since: 2.2
+ **/
HildonTouchSelector *
hildon_picker_dialog_get_selector (HildonPickerDialog * dialog)
{