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