Adding the HildonCalendar based on Gtk Calendar. This effectively changes the license...
[hildon] / src / hildon-get-password-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: Michael Dominic Kostrzewa <michael.kostrzewa@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.
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-get-password-dialog
27  * @short_description: A widget used to get a password.
28  * @see_also: #HildonSetPasswordDialog
29  * 
30  * HildonGetPasswordDialog prompts the user for a password.  It allows
31  * inputting password, with an optional configurable label eg. for
32  * showing a custom message. The maximum length of the password can be set.
33  *
34  * <example>
35  * <title>HildonGetPassword example</title>
36  * <programlisting>
37  * get_dialog =  HILDON_GET_PASSWORD_DIALOG (hildon_get_password_dialog_new (parent, FALSE));
38  * <!-- -->
39  * gtk_widget_show (GTK_WIDGET (get_dialog));
40  * <!-- -->
41  * i = gtk_dialog_run (GTK_DIALOG (get_dialog));
42  * <!-- -->
43  * pass = hildon_get_password_dialog_get_password (get_dialog);
44  * <!-- -->
45  * if (i == GTK_RESPONSE_OK &amp;&amp; (strcmp (pass, dialog.current_password) != 0))
46  * {
47  *      gtk_infoprint (GTK_WINDOW (parent), STR_PASSWORD_INCORRECT);
48  *      gtk_widget_set_sensitive (GTK_WIDGET (dialog.button2), FALSE);
49  *      gtk_widget_set_sensitive (GTK_WIDGET (dialog.button3), FALSE);
50  *      gtk_widget_set_sensitive (GTK_WIDGET (dialog.button4), FALSE);
51  * }
52  * <!-- -->
53  * else if (i == GTK_RESPONSE_OK)
54  * {   
55  *      gtk_widget_set_sensitive( GTK_WIDGET( dialog.button2 ), TRUE);
56  * }
57  * <!-- -->
58  * else
59  * {
60  *      gtk_widget_set_sensitive (GTK_WIDGET (dialog.button2), FALSE);
61  *      gtk_widget_set_sensitive (GTK_WIDGET (dialog.button3), FALSE);
62  *      gtk_widget_set_sensitive (GTK_WIDGET (dialog.button4), FALSE);
63  * }
64  * gtk_widget_destroy (GTK_WIDGET (get_dialog));
65  * }
66  * </programlisting>
67  * </example>
68  */
69
70 #ifdef                                          HAVE_CONFIG_H
71 #include                                        <config.h>
72 #endif
73
74 #include                                        "hildon-get-password-dialog.h"
75 #include                                        <glib.h>
76 #include                                        <errno.h>
77 #include                                        <string.h>
78 #include                                        <strings.h>
79 #include                                        <unistd.h>
80 #include                                        <stdio.h>
81 #include                                        <gtk/gtk.h>
82 #include                                        "hildon-caption.h"
83 #include                                        "hildon-banner.h"
84 #include                                        <libintl.h>
85 #include                                        "hildon-get-password-dialog-private.h"
86
87 #define                                         _(String) dgettext("hildon-libs", String)
88
89 #define                                         HILDON_GET_PASSWORD_DIALOG_TITLE "ecdg_ti_get_old_password"
90
91 #define                                         HILDON_GET_PASSWORD_DIALOG_PASSWORD "ecdg_fi_get_old_pwd_enter_pwd"
92
93 #define                                         HILDON_GET_PASSWORD_DIALOG_OK "ecdg_bd_get_old_password_dialog_ok"
94
95 #define                                         HILDON_GET_PASSWORD_DIALOG_CANCEL "ecdg_bd_get_old_password_dialog_cancel"
96
97 #define                                         HILDON_GET_PASSWORD_VERIFY_DIALOG_TITLE "ecdg_ti_verify_password"
98
99 #define                                         HILDON_GET_PASSWORD_VERIFY_DIALOG_PASSWORD "ecdg_fi_verify_pwd_enter_pwd"
100
101 #define                                         HILDON_GET_PASSWORD_VERIFY_DIALOG_OK "ecdg_bd_verify_password_dialog_ok"
102
103 #define                                         HILDON_GET_PASSWORD_VERIFY_DIALOG_CANCEL "ecdg_bd_verify_password_dialog_cancel"
104
105 #define                                         HILDON_GET_PASSWORD_DIALOG_MAX_CHARS "ckdg_ib_maximum_characters_reached"
106
107 static GtkDialogClass*                          parent_class;
108
109 static void
110 hildon_get_password_dialog_class_init           (HildonGetPasswordDialogClass *class);
111
112 static void
113 hildon_get_password_dialog_init                 (HildonGetPasswordDialog *widget);
114
115 static void
116 hildon_get_password_set_property                (GObject *object,
117                                                  guint prop_id,
118                                                  const GValue *value,
119                                                  GParamSpec *pspec);
120
121 static void
122 hildon_get_password_get_property                (GObject *object,
123                                                  guint prop_id, 
124                                                  GValue *value,
125                                                  GParamSpec *pspec);
126
127 static void 
128 create_contents                                 (HildonGetPasswordDialog *dialog);
129
130 static void 
131 invalid_input                                   (GtkWidget *widget, 
132                                                  GtkInvalidInputType reason, 
133                                                  gpointer unused);
134
135 enum
136 {
137     PROP_0,
138     PROP_MESSAGE,
139     PROP_PASSWORD,
140     PROP_NUMBERS_ONLY,
141     PROP_CAPTION_LABEL,
142     PROP_MAX_CHARS,
143     PROP_GET_OLD
144 };
145
146 /* Private functions */
147 static void
148 hildon_get_password_set_property                (GObject *object,
149                                                  guint prop_id,
150                                                  const GValue *value, 
151                                                  GParamSpec *pspec)
152 {
153     HildonGetPasswordDialog *dialog = HILDON_GET_PASSWORD_DIALOG (object);
154     HildonGetPasswordDialogPrivate *priv;
155
156     priv = HILDON_GET_PASSWORD_DIALOG_GET_PRIVATE (object);
157     g_assert (priv);
158
159     switch (prop_id) {
160
161         case PROP_MESSAGE:
162             /* Set label text representing password domain */
163             gtk_label_set_text (priv->message_label, g_value_get_string (value));
164             break;
165
166         case PROP_PASSWORD:
167             gtk_entry_set_text(GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->password_entry))), 
168                     g_value_get_string(value));
169             break;
170
171         case PROP_NUMBERS_ONLY:
172             /* Set input mode for the password entry */
173             g_object_set(G_OBJECT (gtk_bin_get_child GTK_BIN ((priv->password_entry))),
174                     "hildon-input-mode",
175                     (g_value_get_boolean (value)
176                      ? HILDON_GTK_INPUT_MODE_NUMERIC
177                      : HILDON_GTK_INPUT_MODE_FULL),
178                     NULL);
179             break;
180
181         case PROP_CAPTION_LABEL:
182             hildon_get_password_dialog_set_caption (dialog, g_value_get_string (value));
183             break;
184
185         case PROP_MAX_CHARS:
186             hildon_get_password_dialog_set_max_characters (dialog, g_value_get_int (value));
187             break;
188
189         case PROP_GET_OLD:
190             priv->get_old = g_value_get_boolean (value);
191             create_contents (dialog);
192             break;
193
194         default:
195             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
196             break;
197     }
198 }
199
200 static void
201 hildon_get_password_get_property                (GObject *object,
202                                                  guint prop_id,
203                                                  GValue *value, 
204                                                  GParamSpec *pspec)
205 {
206     HildonGetPasswordDialog *dialog = HILDON_GET_PASSWORD_DIALOG (object);
207     HildonGetPasswordDialogPrivate *priv;
208     const gchar *string;
209     gint max_length;
210     gint input_mode;
211
212     priv = HILDON_GET_PASSWORD_DIALOG_GET_PRIVATE (dialog);
213     g_assert (priv);
214
215     switch (prop_id) {
216
217         case PROP_MESSAGE:
218             string = gtk_label_get_text (priv->message_label);
219             g_value_set_string (value, string);
220             break;
221
222         case PROP_PASSWORD:
223             string = gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->password_entry))));
224             g_value_set_string (value, string);
225             break;
226
227         case PROP_NUMBERS_ONLY:
228             /* This property is set if and only if the input mode
229                of the password entry has been set to numeric only */
230             g_object_get (G_OBJECT (gtk_bin_get_child (GTK_BIN (priv->password_entry))),
231                     "hildon-input-mode", &input_mode, NULL);
232             g_value_set_boolean (value,
233                     (input_mode == HILDON_GTK_INPUT_MODE_NUMERIC));
234             break;
235
236         case PROP_CAPTION_LABEL:
237             string = hildon_caption_get_label (priv->password_entry);
238             g_value_set_string (value, string);
239             break;
240
241         case PROP_MAX_CHARS:
242             max_length = gtk_entry_get_max_length 
243                     (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->password_entry))));
244             g_value_set_int (value, max_length);
245             break;
246
247         case PROP_GET_OLD:
248             g_value_set_boolean (value, priv->get_old);
249             break;
250
251         default:
252             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
253             break;
254     }
255 }
256
257 static void
258 hildon_get_password_dialog_class_init           (HildonGetPasswordDialogClass *class)
259 {
260     GObjectClass *object_class = G_OBJECT_CLASS (class);
261
262     parent_class = g_type_class_peek_parent (class);
263
264     /* Override virtual functions */
265     object_class->set_property = hildon_get_password_set_property;
266     object_class->get_property = hildon_get_password_get_property;
267
268     /* Install new properties */
269     
270     /**
271      * HildonGetPasswordDialog:message:
272      *
273      * Optional message displayed to the user.
274      */
275     g_object_class_install_property 
276         (object_class, 
277          PROP_MESSAGE, 
278          g_param_spec_string ("message",
279              "Message",
280              "Set optional message",
281              NULL,
282              G_PARAM_READWRITE));
283
284     /**
285      * HildonGetPasswordDialog:password:
286      *
287      * Password field contents.
288      */
289     g_object_class_install_property
290         (object_class, 
291          PROP_PASSWORD,
292          g_param_spec_string ("password",
293              "Password",
294              "Password field",
295              "DEFAULT",
296              G_PARAM_READWRITE));
297
298     /**
299      * HildonGetPasswordDialog:numbers-only:
300      *
301      * If the password entry field is operating in numbers-only mode.
302      */
303     g_object_class_install_property
304         (object_class, 
305          PROP_NUMBERS_ONLY,
306          g_param_spec_boolean ("numbers-only",
307              "NumbersOnly",
308              "Set entry to accept only numeric values",
309              FALSE,
310              G_PARAM_READWRITE));
311
312     /**
313      * HildonGetPasswordDialog:caption-label:
314      *
315      * Caption label.
316      */
317     g_object_class_install_property
318         (object_class, 
319          PROP_CAPTION_LABEL,
320          g_param_spec_string ("caption-label",
321              "Caption Label",
322              "The text to be set as the caption label",
323              NULL,
324              G_PARAM_READWRITE));
325     
326     /**
327      * HildonGetPasswordDialog:max-characters:
328      *
329      * Maximum characters than can be entered.
330      */
331     g_object_class_install_property
332         (object_class, 
333          PROP_MAX_CHARS,
334          g_param_spec_int ("max-characters",
335              "Maximum Characters",
336              "The maximum number of characters the password"
337              " dialog accepts",
338              G_MININT,
339              G_MAXINT,
340              0,
341              G_PARAM_READWRITE));
342
343     /**
344      * HildonGetPasswordDialog:get-old:
345      *
346      * If the dialog is used to retrieve an old password or set a new one.
347      */
348     g_object_class_install_property
349         (object_class,
350          PROP_GET_OLD,
351          g_param_spec_boolean ("get-old",
352              "Get Old Password",
353              "TRUE if dialog is a get old password dialog, "
354              "FALSE if dialog is a get password dialog",
355              FALSE,
356              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
357
358     /* Install private structure */
359     g_type_class_add_private (class, sizeof (HildonGetPasswordDialogPrivate));
360 }
361
362 static void
363 hildon_get_password_dialog_init                 (HildonGetPasswordDialog *dialog)
364 {
365     /* Set initial properties for the dialog; the actual contents are
366        created once the 'get-old' property is set with g_object_new */
367
368     gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
369     gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
370     gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
371 }
372
373 static void
374 create_contents                                 (HildonGetPasswordDialog *dialog)
375 {
376     HildonGetPasswordDialogPrivate *priv;
377     GtkSizeGroup * group;
378     GtkWidget *control;
379
380     /* Cache private pointer for faster member access */
381     priv = HILDON_GET_PASSWORD_DIALOG_GET_PRIVATE (dialog);
382     g_assert (priv);
383
384     /* Sizegroup for captions */
385     group = GTK_SIZE_GROUP (gtk_size_group_new
386             (GTK_SIZE_GROUP_HORIZONTAL));
387
388     /* Dialog title */
389     gtk_window_set_title (GTK_WINDOW (dialog),
390             priv->get_old
391             ? _(HILDON_GET_PASSWORD_DIALOG_TITLE)
392             : _(HILDON_GET_PASSWORD_VERIFY_DIALOG_TITLE));
393
394     /* Optional password domain label */
395     priv->message_label = GTK_LABEL (gtk_label_new (NULL));
396
397     /* Create buttons */
398     gtk_dialog_add_button (GTK_DIALOG (dialog),
399                     (priv->get_old
400                      ? _(HILDON_GET_PASSWORD_DIALOG_OK)
401                      : _(HILDON_GET_PASSWORD_VERIFY_DIALOG_OK)),
402                     GTK_RESPONSE_OK);
403
404     gtk_dialog_add_button (GTK_DIALOG (dialog),
405                     (priv->get_old
406                      ? _(HILDON_GET_PASSWORD_DIALOG_CANCEL)
407                      : _(HILDON_GET_PASSWORD_VERIFY_DIALOG_CANCEL)),
408                     GTK_RESPONSE_CANCEL);
409
410     /* Create password text entry */
411     control = gtk_entry_new ();
412     gtk_entry_set_width_chars (GTK_ENTRY (control), 20);
413
414     g_object_set (control, "hildon-input-mode", HILDON_GTK_INPUT_MODE_FULL, NULL);
415
416     gtk_entry_set_visibility (GTK_ENTRY(control), FALSE);
417     priv->password_entry = HILDON_CAPTION
418         (hildon_caption_new(group,
419                             (priv->get_old
420                              ? _(HILDON_GET_PASSWORD_DIALOG_PASSWORD)
421                              : _(HILDON_GET_PASSWORD_VERIFY_DIALOG_PASSWORD)),
422                             control, NULL,
423                             HILDON_CAPTION_OPTIONAL));
424     hildon_caption_set_separator (HILDON_CAPTION (priv->password_entry), "");
425
426     /* Do the basic layout */
427     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
428             GTK_WIDGET (priv->message_label), FALSE, FALSE, 0);
429     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
430             GTK_WIDGET (priv->password_entry), FALSE, FALSE, 0);
431     gtk_widget_show_all (GTK_DIALOG (dialog)->vbox);
432
433     /* Ensure group is freed when all its contents have been removed */
434     g_object_unref (group);
435 }
436
437 /**
438  * hildon_get_password_dialog_get_type:
439  *
440  * Returns GType for HildonGetPasswordDialog as produced by
441  * g_type_register_static().
442  *
443  * Returns: HildonGetPasswordDialog type
444  */
445 GType G_GNUC_CONST
446 hildon_get_password_dialog_get_type             (void)
447 {
448     static GType dialog_type = 0;
449
450     if (! dialog_type) {
451         static const GTypeInfo dialog_info = {
452             sizeof (HildonGetPasswordDialogClass),
453             NULL,       /* base_init */
454             NULL,       /* base_finalize */
455             (GClassInitFunc) hildon_get_password_dialog_class_init,
456             NULL,       /* class_finalize */
457             NULL,       /* class_data */
458             sizeof (HildonGetPasswordDialog),
459             0,  /* n_preallocs */
460             (GInstanceInitFunc) hildon_get_password_dialog_init
461         };
462
463         dialog_type = g_type_register_static (GTK_TYPE_DIALOG,
464                 "HildonGetPasswordDialog",
465                 &dialog_info, 0);
466     }
467     return dialog_type;
468 }
469
470 /**
471  * hildon_get_password_dialog_new:
472  * @parent: parent window; can be NULL
473  * @get_old: FALSE creates a new get password dialog and
474  *           TRUE creates a new get old password dialog. That is,
475  *           if the password to be obtained is the old password, 
476  *           this parameter is specified TRUE.  
477  * 
478  * Construct a new HildonGetPasswordDialog.
479  *
480  * Returns: a new #GtkWidget of type HildonGetPasswordDialog
481  */
482 GtkWidget*
483 hildon_get_password_dialog_new                  (GtkWindow *parent,
484                                                  gboolean get_old)
485 {
486     HildonGetPasswordDialog *dialog = g_object_new
487         (HILDON_TYPE_GET_PASSWORD_DIALOG,
488          "get-old", get_old, NULL);
489
490     if (parent != NULL) {
491         gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
492     }
493
494     return (GtkWidget *) dialog;
495 }
496
497 /**
498  * hildon_get_password_dialog_new_with_default:
499  * @parent: parent window; can be NULL
500  * @password: a default password to be shown in password field
501  * @get_old: FALSE creates a new get password dialog and
502  *           TRUE creates a new get old password dialog. That is,
503  *           if the password to be obtained is the old password,
504  *           this parameter is specified TRUE.
505  *                        
506  * 
507  * Same as #hildon_get_password_dialog_new but with a default password
508  * in password field.
509  *
510  * Returns: a new #GtkWidget of type HildonGetPasswordDialog
511  */
512 GtkWidget*
513 hildon_get_password_dialog_new_with_default     (GtkWindow *parent,
514                                                  const gchar *password,
515                                                  gboolean get_old)
516 {
517     GtkWidget *dialog;
518
519     dialog = hildon_get_password_dialog_new (parent, get_old);
520
521     if (password != NULL)
522         g_object_set (G_OBJECT (dialog), "password", password, NULL);
523
524     return GTK_WIDGET (dialog);
525 }
526
527 /**
528  * hildon_get_password_dialog_get_password:
529  * @dialog: pointer to HildonSetPasswordDialog
530  * 
531  * Gets the currently entered password. The string should not be freed.
532  *
533  * Returns: current password entered by the user.
534  */
535 const gchar*
536 hildon_get_password_dialog_get_password         (HildonGetPasswordDialog *dialog)
537 {
538     GtkEntry *entry1;
539     gchar *text1;
540
541     HildonGetPasswordDialogPrivate *priv;
542
543     g_return_val_if_fail (HILDON_IS_GET_PASSWORD_DIALOG (dialog), NULL);
544     priv = HILDON_GET_PASSWORD_DIALOG_GET_PRIVATE (dialog);
545     g_assert (priv);
546
547     /* Retrieve the password entry widget */
548     entry1 = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->password_entry)));
549     text1 = GTK_ENTRY (entry1)->text;
550
551     return text1;
552 }
553
554 /**
555  * hildon_get_password_dialog_set_message
556  * @dialog: the dialog
557  * @message: a custom message or some other descriptive text to be set
558  * 
559  * Sets the optional descriptive text displayed at the top of the dialog.
560  */
561 void 
562 hildon_get_password_dialog_set_message          (HildonGetPasswordDialog *dialog, 
563                                                  const gchar *message)
564 {
565     HildonGetPasswordDialogPrivate *priv;
566
567     g_return_if_fail (HILDON_IS_GET_PASSWORD_DIALOG (dialog));
568
569     priv = HILDON_GET_PASSWORD_DIALOG_GET_PRIVATE (dialog);
570     g_assert (priv);
571
572     gtk_label_set_text (priv->message_label, message);
573
574 }
575
576 /**
577  * hildon_get_password_dialog_set_caption:
578  * @dialog: the dialog
579  * @new_caption: the text to be set as the caption label
580  * 
581  * Sets the password entry field's neigbouring label.
582  */
583 void 
584 hildon_get_password_dialog_set_caption          (HildonGetPasswordDialog *dialog,
585                                                  const gchar *new_caption)
586 {
587     HildonGetPasswordDialogPrivate *priv;
588
589     g_return_if_fail (HILDON_IS_GET_PASSWORD_DIALOG (dialog));
590     g_return_if_fail (new_caption != NULL);
591
592     priv = HILDON_GET_PASSWORD_DIALOG_GET_PRIVATE (dialog);
593     g_assert (priv);
594
595     hildon_caption_set_label (priv->password_entry, new_caption);
596 }
597
598 /**
599  * hildon_get_password_dialog_set_max_characters:
600  * @dialog: the dialog
601  * @max_characters: the maximum number of characters the password dialog
602  * accepts
603  * 
604  * sets the maximum number of characters allowed as the password
605  */
606 void 
607 hildon_get_password_dialog_set_max_characters   (HildonGetPasswordDialog *dialog, 
608                                                  gint max_characters)
609 {
610     HildonGetPasswordDialogPrivate *priv;
611
612     g_return_if_fail (max_characters > 0);
613     g_return_if_fail (HILDON_IS_GET_PASSWORD_DIALOG (dialog));
614
615     priv = HILDON_GET_PASSWORD_DIALOG_GET_PRIVATE (dialog);
616     g_assert (priv);
617
618     /* Apply the given length to password entry */
619     gtk_entry_set_max_length (GTK_ENTRY
620             (gtk_bin_get_child
621              GTK_BIN ((priv->password_entry))),
622              max_characters);
623
624     /* FIXME There is a bug here -- the prev. signal needs to be
625      * disconnected before connecting the new signal. Besides, this 
626      * should go into the constructor */
627
628     /* Connect callback to show error banner if the limit is exceeded */
629     g_signal_connect (GTK_ENTRY
630             (gtk_bin_get_child
631              GTK_BIN ((priv->password_entry))),
632             "invalid_input",
633             G_CALLBACK (invalid_input),
634             NULL
635             );
636 }
637
638 /* Callback that gets called when maximum chars is reached in the entry */
639 static void 
640 invalid_input                                   (GtkWidget *widget, 
641                                                  GtkInvalidInputType reason, 
642                                                  gpointer unused) 
643 {
644     if (reason == GTK_INVALID_INPUT_MAX_CHARS_REACHED) 
645     {
646         hildon_banner_show_information (widget, NULL, _(HILDON_GET_PASSWORD_DIALOG_MAX_CHARS));
647     }
648 }