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