[ekiga/ds-gtk-application] FormDialog: Several HIG3 text entry enhancements.



commit 0fb1bc8b387f4363391628f81070e194c4cb934e
Author: Damien Sandras <dsandras seconix com>
Date:   Sat Oct 11 13:27:01 2014 +0200

    FormDialog: Several HIG3 text entry enhancements.
    
    Text entries in forms have been enhanced with basic features:
      - The specific PrivateText/PrivateTextSubmitter code has been removed.
    
      We now have only one Text/TextSubmitter object allowing different
      types of text to be entered: standard text, password, URI and phone
      number. Each Text/TextSubmitter allows empty values or not.
    
      - The GtkDialog will disallow validation if basic regexes on one of
        its various TextSubmitters does not validate. It is for example
        impossible to enter invalid URIs. Regexes are only basic checks.
        More advanced checks can be achieved after the Form has been
        submitted by the core components using it.
    
      - GtkEntries now have an edit-clear-symbolic icon (when not empty)
        allowing the delete the full content at once.

 lib/engine/components/opal/opal-account.cpp    |    9 +-
 lib/engine/components/opal/opal-bank.cpp       |   10 +-
 lib/engine/components/opal/opal-presentity.cpp |    8 +-
 lib/engine/framework/form-builder.cpp          |   41 +----
 lib/engine/framework/form-builder.h            |   16 +--
 lib/engine/framework/form-dumper.cpp           |   17 +--
 lib/engine/framework/form-dumper.h             |    7 +-
 lib/engine/framework/form-visitor.h            |   13 +-
 lib/engine/framework/form.cpp                  |    6 -
 lib/engine/framework/form.h                    |    4 -
 lib/engine/gui/gtk-core/form-dialog-gtk.cpp    |  227 +++++++++++++-----------
 lib/engine/gui/gtk-core/form-dialog-gtk.h      |   17 +-
 plugins/ldap/ldap-book.cpp                     |    8 +-
 plugins/loudmouth/loudmouth-account.cpp        |    4 +-
 plugins/loudmouth/loudmouth-bank.cpp           |    4 +-
 plugins/resource-list/rl-cluster.cpp           |    4 +-
 plugins/resource-list/rl-heap.cpp              |    4 +-
 17 files changed, 178 insertions(+), 221 deletions(-)
---
diff --git a/lib/engine/components/opal/opal-account.cpp b/lib/engine/components/opal/opal-account.cpp
index 1407786..e5296ad 100644
--- a/lib/engine/components/opal/opal-account.cpp
+++ b/lib/engine/components/opal/opal-account.cpp
@@ -652,8 +652,11 @@ Opal::Account::edit ()
      */
     request->text ("authentication_user", _("Login"), get_authentication_username (),
                    _("jon.doe"));
-  request->private_text ("password", _("Password"), get_password (),
-                         _("1234"));
+  request->text ("password",
+                 _("Password"),
+                 get_password (),
+                 _("1234"),
+                 Ekiga::FormVisitor::PASSWORD);
   request->text ("timeout", _("Timeout"), str.str (), _("3600"));
   request->boolean ("enabled", _("Enable Account"), is_enabled ());
 
@@ -677,7 +680,7 @@ Opal::Account::on_edit_form_submitted (bool submitted,
     new_authentication_user = result.text ("authentication_user");
   if (new_authentication_user.empty ())
     new_authentication_user = new_user;
-  std::string new_password = result.private_text ("password");
+  std::string new_password = result.text ("password");
   bool new_enabled = result.boolean ("enabled");
   bool should_enable = false;
   bool should_disable = false;
diff --git a/lib/engine/components/opal/opal-bank.cpp b/lib/engine/components/opal/opal-bank.cpp
index 3cbb174..03a19f9 100644
--- a/lib/engine/components/opal/opal-bank.cpp
+++ b/lib/engine/components/opal/opal-bank.cpp
@@ -180,7 +180,7 @@ Opal::Bank::new_account (Account::Type acc_type,
     request->hidden ("host", "ekiga.net");
     request->text ("user", _("_User:"), username, _("The user name, e.g. jim"));
     request->hidden ("authentication_user", username);
-    request->private_text ("password", _("_Password:"), password, _("Password associated to the user"));
+    request->text ("password", _("_Password:"), password, _("Password associated to the user"), 
Ekiga::FormVisitor::PASSWORD);
     request->hidden ("timeout", "3600");
     break;
 
@@ -191,7 +191,7 @@ Opal::Bank::new_account (Account::Type acc_type,
     request->hidden ("host", "sip.diamondcard.us");
     request->text ("user", _("_Account ID:"), username, _("The user name, e.g. jim"));
     request->hidden ("authentication_user", username);
-    request->private_text ("password", _("_PIN code:"), password, _("Password associated to the user"));
+    request->text ("password", _("_PIN code:"), password, _("Password associated to the user"), 
Ekiga::FormVisitor::PASSWORD);
     request->hidden ("timeout", "3600");
     break;
 
@@ -200,7 +200,7 @@ Opal::Bank::new_account (Account::Type acc_type,
     request->text ("host", _("_Gatekeeper:"), std::string (), _("The gatekeeper, e.g. ekiga.net"));
     request->text ("user", _("_User:"), username, _("The user name, e.g. jim"));
     request->hidden ("authentication_user", username);
-    request->private_text ("password", _("_Password:"), password, _("Password associated to the user"));
+    request->text ("password", _("_Password:"), password, _("Password associated to the user"), 
Ekiga::FormVisitor::PASSWORD);
     request->text ("timeout", _("_Timeout:"), "3600", _("Time in seconds after which the account 
registration is automatically retried"));
     break;
 
@@ -210,7 +210,7 @@ Opal::Bank::new_account (Account::Type acc_type,
     request->text ("host", _("_Registrar:"), std::string (), _("The registrar, e.g. ekiga.net"));
     request->text ("user", _("_User:"), username, _("The user name, e.g. jim"));
     request->text ("authentication_user", _("_Authentication user:"), std::string (), _("The user name used 
during authentication, if different than the user name; leave empty if you do not have one"));
-    request->private_text ("password", _("_Password:"), password, _("Password associated to the user"));
+    request->text ("password", _("_Password:"), password, _("Password associated to the user"), 
Ekiga::FormVisitor::PASSWORD);
     request->text ("timeout", _("_Timeout:"), "3600", _("Time in seconds after which the account 
registration is automatically retried"));
     break;
   }
@@ -237,7 +237,7 @@ Opal::Bank::on_new_account_form_submitted (bool submitted,
                          || acc_type == Opal::Account::H323) ? result.text ("host") : result.hidden ("host");
   std::string new_user = result.text ("user");
   std::string new_authentication_user = (acc_type == Opal::Account::SIP) ? result.text 
("authentication_user") : new_user;
-  std::string new_password = result.private_text ("password");
+  std::string new_password = result.text ("password");
   bool new_enabled = result.boolean ("enabled");
   unsigned new_timeout = atoi ((acc_type == Opal::Account::SIP
                                || acc_type == Opal::Account::H323) ?
diff --git a/lib/engine/components/opal/opal-presentity.cpp b/lib/engine/components/opal/opal-presentity.cpp
index dfea858..0c94a12 100644
--- a/lib/engine/components/opal/opal-presentity.cpp
+++ b/lib/engine/components/opal/opal-presentity.cpp
@@ -265,10 +265,14 @@ Opal::Presentity::edit_presentity ()
   request->action (_("Done"));
   request->text ("name", _("Name"),
                  get_name (),
-                 _("John Doe"), false, false);
+                 _("John Doe"),
+                 Ekiga::FormVisitor::STANDARD,
+                 false, false);
   request->text ("uri", _("URI"),
                  get_uri (),
-                 _("sip:username ekiga net"), false, false);
+                 _("sip:username ekiga net"),
+                 Ekiga::FormVisitor::URI,
+                 false, false);
 
   request->editable_list ("groups", _("Groups"),
                         get_groups (), existing_groups ());
diff --git a/lib/engine/framework/form-builder.cpp b/lib/engine/framework/form-builder.cpp
index 91d7225..44d2cec 100644
--- a/lib/engine/framework/form-builder.cpp
+++ b/lib/engine/framework/form-builder.cpp
@@ -46,7 +46,6 @@ Ekiga::FormBuilder::visit (Ekiga::FormVisitor &visitor) const
   std::list<struct HiddenField>::const_iterator iter_hidden = hiddens.begin ();
   std::list<struct BooleanField>::const_iterator iter_bool = booleans.begin ();
   std::list<struct TextField>::const_iterator iter_text = texts.begin ();
-  std::list<struct TextField>::const_iterator iter_private_text = private_texts.begin ();
   std::list<struct MultiTextField>::const_iterator iter_multi_text = multi_texts.begin ();
   std::list<struct SingleChoiceField>::const_iterator iter_single_choice = single_choices.begin ();
   std::list<struct MultipleChoiceField>::const_iterator iter_multiple_choice = multiple_choices.begin ();
@@ -84,21 +83,10 @@ Ekiga::FormBuilder::visit (Ekiga::FormVisitor &visitor) const
 
       visitor.text (iter_text->name, iter_text->description,
                     iter_text->value, iter_text->tooltip,
-                    iter_text->advanced, iter_text->allow_empty);
+                    iter_text->type, iter_text->advanced, iter_text->allow_empty);
       iter_text++;
       break;
 
-    case PRIVATE_TEXT:
-
-      visitor.private_text (iter_private_text->name,
-                           iter_private_text->description,
-                           iter_private_text->value,
-                           iter_private_text->tooltip,
-                           iter_private_text->advanced,
-                           iter_private_text->allow_empty);
-      iter_private_text++;
-      break;
-
     case MULTI_TEXT:
 
       visitor.multi_text (iter_multi_text->name,
@@ -170,18 +158,6 @@ Ekiga::FormBuilder::boolean (const std::string name) const
 }
 
 const std::string
-Ekiga::FormBuilder::private_text (const std::string name) const
-{
-  for (std::list<struct TextField>::const_iterator iter = private_texts.begin ();
-       iter != private_texts.end ();
-       iter++)
-    if (iter->name == name)
-      return iter->value;
-
-  return ""; // shouldn't happen
-}
-
-const std::string
 Ekiga::FormBuilder::text (const std::string name) const
 {
   for (std::list<struct TextField>::const_iterator iter = texts.begin ();
@@ -296,26 +272,15 @@ Ekiga::FormBuilder::text (const std::string name,
                          const std::string description,
                          const std::string value,
                          const std::string tooltip,
+                          const FormVisitor::FormTextType type,
                          bool advanced,
                           bool allow_empty)
 {
-  texts.push_back (TextField (name, description, value, tooltip, advanced, allow_empty));
+  texts.push_back (TextField (name, description, value, tooltip, type, advanced, allow_empty));
   ordering.push_back (TEXT);
 }
 
 void
-Ekiga::FormBuilder::private_text (const std::string name,
-                                 const std::string description,
-                                 const std::string value,
-                                 const std::string tooltip,
-                                  bool advanced,
-                                  bool allow_empty)
-{
-  private_texts.push_back (TextField (name, description, value, tooltip, advanced, allow_empty));
-  ordering.push_back (PRIVATE_TEXT);
-}
-
-void
 Ekiga::FormBuilder::multi_text (const std::string name,
                                const std::string description,
                                const std::string value,
diff --git a/lib/engine/framework/form-builder.h b/lib/engine/framework/form-builder.h
index 8c1cb3f..8fa2a27 100644
--- a/lib/engine/framework/form-builder.h
+++ b/lib/engine/framework/form-builder.h
@@ -64,8 +64,6 @@ namespace Ekiga
 
     const std::string text (const std::string name) const;
 
-    const std::string private_text (const std::string name) const;
-
     const std::string multi_text (const std::string name) const;
 
     const std::string single_choice (const std::string name) const;
@@ -75,7 +73,6 @@ namespace Ekiga
     const std::list<std::string> editable_list (const std::string name) const;
 
     /* builder part */
-
     void title (const std::string title);
 
     void action (const std::string action);
@@ -99,16 +96,10 @@ namespace Ekiga
               const std::string description,
               const std::string value,
               const std::string tooltip,
+               const FormTextType type = STANDARD,
               bool advanced = false,
                bool allow_empty = true);
 
-    void private_text (const std::string text,
-                      const std::string description,
-                      const std::string value,
-                      const std::string tooltip,
-                       bool advanced = false,
-                       bool allow_empty = true);
-
     void multi_text (const std::string text,
                     const std::string description,
                     const std::string value,
@@ -167,11 +158,13 @@ namespace Ekiga
                 const std::string _description,
                 const std::string _value,
                 const std::string _tooltip,
+                 const FormTextType _type,
                 bool _advanced,
                  bool _allow_empty): name(_name),
                                      description(_description),
                                      value(_value),
                                      tooltip (_tooltip),
+                                     type(_type),
                                      advanced(_advanced),
                                      allow_empty(_allow_empty)
       {}
@@ -180,6 +173,7 @@ namespace Ekiga
       const std::string description;
       const std::string value;
       const std::string tooltip;
+      const FormTextType type;
       bool advanced;
       bool allow_empty;
     };
@@ -266,7 +260,6 @@ namespace Ekiga
       HIDDEN,
       BOOLEAN,
       TEXT,
-      PRIVATE_TEXT,
       MULTI_TEXT,
       SINGLE_CHOICE,
       MULTIPLE_CHOICE,
@@ -282,7 +275,6 @@ namespace Ekiga
     std::list<struct HiddenField> hiddens;
     std::list<struct BooleanField> booleans;
     std::list<struct TextField> texts;
-    std::list<struct TextField> private_texts;
     std::list<struct MultiTextField> multi_texts;
     std::list<struct SingleChoiceField> single_choices;
     std::list<struct MultipleChoiceField> multiple_choices;
diff --git a/lib/engine/framework/form-dumper.cpp b/lib/engine/framework/form-dumper.cpp
index db86d3c..ff3192b 100644
--- a/lib/engine/framework/form-dumper.cpp
+++ b/lib/engine/framework/form-dumper.cpp
@@ -104,27 +104,14 @@ void
 Ekiga::FormDumper::text (const std::string name,
                         const std::string description,
                         const std::string value,
+                         const FormVisitor::FormTextType type,
                         bool advanced,
                          bool allow_empty)
 {
   out << "Text field " << name
       << " (default value: " << value << "): " << std::endl
       << description
-      << (advanced?"[advanced]":"")
-      << (allow_empty?"[allow_empty]":"")
-      << std::endl;
-}
-
-void
-Ekiga::FormDumper::private_text (const std::string name,
-                                const std::string description,
-                                const std::string value,
-                                bool advanced,
-                                 bool allow_empty)
-{
-  out << "Private text field " << name
-      << " (default value: " << value << "): " << std::endl
-      << description
+      << " (Type: " << type << "): " << std::endl
       << (advanced?"[advanced]":"")
       << (allow_empty?"[allow_empty]":"")
       << std::endl;
diff --git a/lib/engine/framework/form-dumper.h b/lib/engine/framework/form-dumper.h
index 8279aee..1518527 100644
--- a/lib/engine/framework/form-dumper.h
+++ b/lib/engine/framework/form-dumper.h
@@ -79,15 +79,10 @@ namespace Ekiga
     void text (const std::string name,
               const std::string description,
               const std::string value,
+               const FormVisitor::FormTextType type,
               bool advanced,
                bool allow_empty);
 
-    void private_text (const std::string name,
-                      const std::string description,
-                      const std::string value,
-                      bool advanced,
-                       bool allow_empty);
-
     void multi_text (const std::string name,
                     const std::string description,
                     const std::string value,
diff --git a/lib/engine/framework/form-visitor.h b/lib/engine/framework/form-visitor.h
index 0af4f83..fb04883 100644
--- a/lib/engine/framework/form-visitor.h
+++ b/lib/engine/framework/form-visitor.h
@@ -41,14 +41,14 @@
 #include <list>
 #include <string>
 
+#include "form.h"
+
 namespace Ekiga
 {
-
 /**
  * @addtogroup forms
  * @{
  */
-
   class FormVisitor
   {
   public:
@@ -74,20 +74,15 @@ namespace Ekiga
                          bool value,
                          bool advanced) = 0;
 
+    typedef enum { STANDARD, PHONE_NUMBER, URI, PASSWORD } FormTextType;
     virtual void text (const std::string name,
                       const std::string description,
                       const std::string value,
                       const std::string tooltip,
+                       const FormTextType type,
                       bool advanced,
                        bool allow_empty) = 0;
 
-    virtual void private_text (const std::string name,
-                              const std::string description,
-                              const std::string tooltip,
-                              const std::string value,
-                               bool advanced,
-                               bool allow_empty) = 0;
-
     virtual void multi_text (const std::string name,
                             const std::string description,
                             const std::string value,
diff --git a/lib/engine/framework/form.cpp b/lib/engine/framework/form.cpp
index 48da40d..ee6bb81 100644
--- a/lib/engine/framework/form.cpp
+++ b/lib/engine/framework/form.cpp
@@ -68,12 +68,6 @@ Ekiga::EmptyForm::text (const std::string /*name*/) const
 }
 
 const std::string
-Ekiga::EmptyForm::private_text (const std::string /*name*/) const
-{
-  return "";
-}
-
-const std::string
 Ekiga::EmptyForm::multi_text (const std::string /*name*/) const
 {
   return "";
diff --git a/lib/engine/framework/form.h b/lib/engine/framework/form.h
index 34f2383..b81babd 100644
--- a/lib/engine/framework/form.h
+++ b/lib/engine/framework/form.h
@@ -60,8 +60,6 @@ namespace Ekiga
 
     virtual const std::string text (const std::string name) const = 0;
 
-    virtual const std::string private_text (const std::string name) const = 0;
-
     virtual const std::string multi_text (const std::string name) const = 0;
 
     virtual const std::string single_choice (const std::string name) const = 0;
@@ -91,8 +89,6 @@ namespace Ekiga
 
     const std::string text (const std::string name) const;
 
-    const std::string private_text (const std::string name) const;
-
     const std::string multi_text (const std::string name) const;
 
     const std::string single_choice (const std::string name) const;
diff --git a/lib/engine/gui/gtk-core/form-dialog-gtk.cpp b/lib/engine/gui/gtk-core/form-dialog-gtk.cpp
index 63a84ab..8d6f091 100644
--- a/lib/engine/gui/gtk-core/form-dialog-gtk.cpp
+++ b/lib/engine/gui/gtk-core/form-dialog-gtk.cpp
@@ -36,6 +36,7 @@
 
 
 #include <glib/gi18n.h>
+#include <ptlib.h>
 
 #include "platform.h"
 #include "form-dialog-gtk.h"
@@ -44,6 +45,14 @@
  * Declarations : GTK+ Callbacks
  */
 
+/** Called when the GtkEntry delete icon has been clicked.
+ *
+ * Delete the entry content.
+ */
+static void
+text_entry_icon_release_cb (GtkEntry *entry,
+                            G_GNUC_UNUSED gpointer data);
+
 
 /** Called when a GtkEntry has new content.
  *
@@ -51,7 +60,10 @@
  * the "OK" button will stay unsensitive as long as
  * the entry does not contain non-empty text.
  *
- * @param: data is a pointer to the Form GtkDialog.
+ * A delete all icon also appears when the entry is not
+ * empty.
+ *
+ * @param: data is a pointer to the FormDialog object.
  */
 static void
 text_entry_changed_cb (GtkEntry *entry,
@@ -142,8 +154,7 @@ link_clicked_cb (GtkWidget *widget,
                  gpointer data);
 
 
-/*
- * Declarations and implementation : the various submitters
+/* Declarations and implementation : the various submitters
  * of a Form
  */
 class TitleSubmitter: public Submitter
@@ -167,6 +178,7 @@ private:
   const std::string title;
 };
 
+
 class ActionSubmitter: public Submitter
 {
 public:
@@ -188,6 +200,7 @@ private:
   const std::string action;
 };
 
+
 class InstructionsSubmitter: public Submitter
 {
 public:
@@ -271,64 +284,67 @@ public:
   TextSubmitter (const std::string _name,
                 const std::string _description,
                 const std::string _placeholder_text,
+                 const Ekiga::FormVisitor::FormTextType _type,
                 bool _advanced,
                 bool _allow_empty,
                 GtkWidget *_widget): name(_name),
                                      description(_description),
                                      placeholder_text(_placeholder_text),
+                                     type(_type),
                                      advanced(_advanced),
                                      allow_empty(_allow_empty),
+                                      submit_ok (false),
                                      widget(_widget)
   { }
 
   ~TextSubmitter ()
   { }
 
-  void submit (Ekiga::FormBuilder &builder)
+  void updated ()
   {
-    builder.text (name,
-                  description,
-                  gtk_entry_get_text (GTK_ENTRY (widget)), placeholder_text,
-                  advanced,
-                  allow_empty);
-  }
+    const std::string value = gtk_entry_get_text (GTK_ENTRY (widget));
+    bool empty = value.empty ();
+    bool empty_ok = (allow_empty || (!empty && value.find_first_not_of (' ') != std::string::npos));
+    bool type_ok = false;
 
-private:
+    switch (type) {
 
-  const std::string name;
-  const std::string description;
-  const std::string placeholder_text;
-  bool advanced;
-  bool allow_empty;
-  GtkWidget *widget;
-};
+    case Ekiga::FormVisitor::URI:
+      type_ok =
+        PString (value).MatchesRegEx (PRegularExpression ("[A-Za-z0-9:_\\-\\ ]+ [A-Za-z0-9\\-\\ ]+",
+                                                          PRegularExpression::Extended));
+      break;
 
+    case Ekiga::FormVisitor::PHONE_NUMBER:
+      type_ok =
+        PString (value).MatchesRegEx (PRegularExpression ("\\+?[0-9]+",
+                                                          PRegularExpression::Extended));
+      break;
 
-class PrivateTextSubmitter: public Submitter
-{
-public:
+    case Ekiga::FormVisitor::STANDARD:
+    case Ekiga::FormVisitor::PASSWORD:
+    default:
+      type_ok = true;
+      break;
+    }
 
-  PrivateTextSubmitter (const std::string _name,
-                       const std::string _description,
-                       bool _advanced,
-                       bool _allow_empty,
-                       GtkWidget *_widget): name(_name),
-                                            description(_description),
-                                            advanced(_advanced),
-                                            allow_empty(_allow_empty),
-                                            widget(_widget)
-  { }
+    submit_ok = (type_ok && empty_ok);
+  }
 
-  ~PrivateTextSubmitter ()
-  { }
+  bool can_submit ()
+  {
+    return submit_ok;
+  }
 
   void submit (Ekiga::FormBuilder &builder)
   {
-    builder.private_text (name, description,
-                         gtk_entry_get_text (GTK_ENTRY (widget)),
-                         placeholder_text,
-                          advanced,
-                          allow_empty);
+    builder.text (name,
+                  description,
+                  gtk_entry_get_text (GTK_ENTRY (widget)),
+                  placeholder_text,
+                  type,
+                  advanced,
+                  allow_empty);
   }
 
 private:
@@ -336,8 +352,10 @@ private:
   const std::string name;
   const std::string description;
   const std::string placeholder_text;
+  const Ekiga::FormVisitor::FormTextType type;
   bool advanced;
   bool allow_empty;
+  bool submit_ok;
   GtkWidget *widget;
 };
 
@@ -570,7 +588,6 @@ private:
 /*
  * GTK+ Callbacks
  */
-
 static void
 editable_list_add_value_activated_cb (GtkWidget *entry,
                                     gpointer data)
@@ -690,15 +707,36 @@ editable_list_choice_toggled_cb (G_GNUC_UNUSED GtkCellRendererToggle *cell,
 
 
 static void
+text_entry_icon_release_cb (GtkEntry *entry,
+                            G_GNUC_UNUSED gpointer data)
+{
+  gtk_entry_set_text (entry, "");
+  gtk_widget_grab_focus (GTK_WIDGET(entry));
+}
+
+
+static void
 text_entry_changed_cb (GtkEntry *entry,
                        gpointer data)
 {
   g_return_if_fail (data);
-  std::string value = gtk_entry_get_text (entry);
-  bool sensitive = (!value.empty () && value.find_first_not_of (' ') != std::string::npos);
 
-  gtk_widget_set_sensitive (gtk_dialog_get_widget_for_response (GTK_DIALOG (data), GTK_RESPONSE_ACCEPT),
-                            sensitive);
+  TextSubmitter *submitter = (TextSubmitter *) g_object_get_data (G_OBJECT (entry), "submitter");
+  FormDialog *form_dialog = (FormDialog *) data;
+  GtkWidget *dialog = form_dialog->get_dialog ();
+  GtkWidget *ok_button = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
+  bool empty = (gtk_entry_get_text_length (entry) == 0);
+  gboolean rtl = (gtk_widget_get_direction (GTK_WIDGET(entry)) == GTK_TEXT_DIR_RTL);
+
+  g_object_set (entry,
+                "secondary-icon-name", !empty ? (rtl ? "edit-clear-rtl-symbolic" : "edit-clear-symbolic") : 
NULL,
+                "secondary-icon-activatable", !empty,
+                "secondary-icon-sensitive", !empty,
+                NULL);
+
+  submitter->updated ();
+
+  gtk_widget_set_sensitive (ok_button, form_dialog->can_submit ());
 }
 
 
@@ -987,12 +1025,12 @@ FormDialog::text (const std::string name,
                  const std::string description,
                  const std::string value,
                  const std::string placeholder_text,
+                  const Ekiga::FormVisitor::FormTextType type,
                  bool advanced,
                   bool allow_empty)
 {
   GtkWidget *label = NULL;
   GtkWidget *entry = NULL;
-  bool sensitive = false;
 
   TextSubmitter *submitter = NULL;
 
@@ -1008,68 +1046,38 @@ FormDialog::text (const std::string name,
   gtk_entry_set_text (GTK_ENTRY (entry), value.c_str ());
   g_object_set (G_OBJECT (entry), "expand", TRUE, NULL);
 
-  if (!allow_empty) {
-    sensitive = (!value.empty () && value.find_first_not_of (' ') != std::string::npos);
-    gtk_widget_set_sensitive (gtk_dialog_get_widget_for_response (GTK_DIALOG (window), GTK_RESPONSE_ACCEPT),
-                              sensitive);
-    g_signal_connect (entry, "changed",
-                      G_CALLBACK (text_entry_changed_cb), window);
-  }
-
-  if (advanced) {
-
-    gtk_grid_attach (GTK_GRID (advanced_fields), label,
-                    0, advanced_rows - 1,
-                    1, 1);
-    gtk_grid_attach (GTK_GRID (advanced_fields), entry,
-                    1, advanced_rows - 1,
-                    1, 1);
-  } else {
-
-    gtk_grid_attach (GTK_GRID (fields), label,
-                    0, rows - 1,
-                    1, 1);
-    gtk_grid_attach (GTK_GRID (fields), entry,
-                    1, rows - 1,
-                    1, 1);
-  }
+  switch (type) {
+    case PASSWORD:
+      gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
+      gtk_entry_set_input_purpose (GTK_ENTRY (entry), GTK_INPUT_PURPOSE_PASSWORD);
+      break;
+    case PHONE_NUMBER:
+      gtk_entry_set_input_purpose (GTK_ENTRY (entry), GTK_INPUT_PURPOSE_PHONE);
+      break;
+    case URI:
+      gtk_entry_set_input_purpose (GTK_ENTRY (entry), GTK_INPUT_PURPOSE_URL);
+      break;
+    case STANDARD:
+    default:
+      break;
+  };
 
-  submitter = new TextSubmitter (name, description, placeholder_text, advanced, allow_empty, entry);
+  submitter = new TextSubmitter (name, description, placeholder_text, type, advanced, allow_empty, entry);
   submitters.push_back (submitter);
-}
-
-
-void
-FormDialog::private_text (const std::string name,
-                         const std::string description,
-                         const std::string value,
-                         const std::string placeholder_text,
-                         bool advanced,
-                          bool allow_empty)
-{
-  GtkWidget *label = NULL;
-  GtkWidget *widget = NULL;
-  PrivateTextSubmitter *submitter = NULL;
-
-  grow_fields (advanced);
 
-  label = gtk_label_new (description.c_str ());
-  gtk_widget_set_halign (GTK_WIDGET (label), GTK_ALIGN_END);
-
-  widget = gtk_entry_new ();
-  gtk_entry_set_placeholder_text (GTK_ENTRY (widget), placeholder_text.c_str ());
-  gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
-  gtk_entry_set_activates_default (GTK_ENTRY (widget), true);
-  gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE);
-  gtk_entry_set_text (GTK_ENTRY (widget), value.c_str ());
-  g_object_set (G_OBJECT (widget), "expand", TRUE, NULL);
+  g_object_set_data (G_OBJECT (entry), "submitter", submitter);
+  text_entry_changed_cb (GTK_ENTRY (entry), (gpointer) this);
+  g_signal_connect (entry, "changed",
+                    G_CALLBACK (text_entry_changed_cb), this);
+  g_signal_connect(entry, "icon-release",
+                   G_CALLBACK (text_entry_icon_release_cb), entry);
 
   if (advanced) {
 
     gtk_grid_attach (GTK_GRID (advanced_fields), label,
                     0, advanced_rows - 1,
                     1, 1);
-    gtk_grid_attach (GTK_GRID (advanced_fields), widget,
+    gtk_grid_attach (GTK_GRID (advanced_fields), entry,
                     1, advanced_rows - 1,
                     1, 1);
   } else {
@@ -1077,13 +1085,10 @@ FormDialog::private_text (const std::string name,
     gtk_grid_attach (GTK_GRID (fields), label,
                     0, rows - 1,
                     1, 1);
-    gtk_grid_attach (GTK_GRID (fields), widget,
+    gtk_grid_attach (GTK_GRID (fields), entry,
                     1, rows - 1,
                     1, 1);
   }
-
-  submitter = new PrivateTextSubmitter (name, description, advanced, allow_empty, widget);
-  submitters.push_back (submitter);
 }
 
 
@@ -1314,6 +1319,7 @@ FormDialog::multiple_choice (const std::string name,
   submitters.push_back (submitter);
 }
 
+
 void
 FormDialog::editable_list (const std::string name,
                            const std::string description,
@@ -1466,6 +1472,19 @@ FormDialog::editable_list (const std::string name,
 
 
 bool
+FormDialog::can_submit ()
+{
+  for (std::list<Submitter *>::iterator iter = submitters.begin ();
+       iter != submitters.end ();
+       iter++)
+    if (!(*iter)->can_submit ())
+      return false;
+
+  return true;
+}
+
+
+bool
 FormDialog::submit ()
 {
   bool ok = false;
@@ -1484,6 +1503,12 @@ FormDialog::submit ()
 }
 
 
+GtkWidget *
+FormDialog::get_dialog ()
+{
+  return window;
+}
+
 void
 FormDialog::cancel ()
 {
diff --git a/lib/engine/gui/gtk-core/form-dialog-gtk.h b/lib/engine/gui/gtk-core/form-dialog-gtk.h
index 90898d5..ddce3d6 100644
--- a/lib/engine/gui/gtk-core/form-dialog-gtk.h
+++ b/lib/engine/gui/gtk-core/form-dialog-gtk.h
@@ -40,6 +40,7 @@
 
 #include "form-builder.h"
 #include "form-request.h"
+#include "form-visitor.h"
 
 /* abstract helper class common to all field types */
 class Submitter
@@ -48,9 +49,12 @@ public:
 
   virtual ~Submitter () {}
 
+  virtual bool can_submit () { return true; }
+
   virtual void submit (Ekiga::FormBuilder &builder) = 0;
 };
 
+
 class FormDialog: public Ekiga::FormVisitor
 {
 public:
@@ -63,7 +67,6 @@ public:
   void run ();
 
   /* FormVisitor api */
-
   void title (const std::string title);
 
   void action (const std::string action);
@@ -87,16 +90,10 @@ public:
             const std::string description,
             const std::string value,
             const std::string placeholder_text,
+             const FormVisitor::FormTextType type,
             bool advanced,
              bool allow_empty);
 
-  void private_text (const std::string name,
-                    const std::string description,
-                    const std::string value,
-                     const std::string placeholder_text,
-                     bool advanced,
-                     bool allow_empty);
-
   void multi_text (const std::string name,
                   const std::string description,
                   const std::string value,
@@ -124,8 +121,12 @@ public:
   /* those are public only to be called from C code */
   void cancel ();
 
+  bool can_submit ();
+
   bool submit ();
 
+  GtkWidget *get_dialog ();
+
 private:
 
   void grow_fields (bool advanced);
diff --git a/plugins/ldap/ldap-book.cpp b/plugins/ldap/ldap-book.cpp
index 2601345..c4aa704 100644
--- a/plugins/ldap/ldap-book.cpp
+++ b/plugins/ldap/ldap-book.cpp
@@ -617,7 +617,7 @@ extern "C" {
 
          /* private text or not? */
          if (noecho) {
-           request->private_text (std::string (resbuf), prompt, "", std::string ());
+           request->text (std::string (resbuf), prompt, "", std::string (), Ekiga::FormVisitor::PASSWORD);
          } else {
            std::string dflt;
            if (in->defresult)
@@ -656,7 +656,7 @@ extern "C" {
              break;
            }
          if (noecho)
-           prompt = result.private_text (std::string (resbuf));
+           prompt = result.text (std::string (resbuf));
          else
            prompt = result.text (std::string (resbuf));
 
@@ -986,7 +986,7 @@ OPENLDAP::BookForm (boost::shared_ptr<Ekiga::FormRequestSimple> request,
    * is anonymous / unauthenticated.)
    */
   request->text ("authcID", _("Bind _ID:"), info.authcID, _("User ID; leave blank for anonymous / 
nonauthenticated"));
-  request->private_text ("password", _("_Password:"), info.password, _("The password for the user ID above, 
if any"));
+  request->text ("password", _("_Password:"), info.password, _("The password for the user ID above, if 
any"), Ekiga::FormVisitor::PASSWORD);
   request->boolean ("startTLS", _("Use _TLS"), info.starttls);
   request->boolean ("sasl", _("Use SAS_L"), info.sasl);
   {
@@ -1063,7 +1063,7 @@ OPENLDAP::BookFormInfo (Ekiga::Form &result,
     result.single_choice ("scope") + "?" +
     result.text ("filter");
   bookinfo.authcID = result.text ("authcID");
-  bookinfo.password = result.private_text ("password");
+  bookinfo.password = result.text ("password");
   bookinfo.starttls = result.boolean ("startTLS");
   bookinfo.sasl = result.boolean ("sasl");
   bookinfo.saslMech = result.single_choice ("saslMech");
diff --git a/plugins/loudmouth/loudmouth-account.cpp b/plugins/loudmouth/loudmouth-account.cpp
index 1466751..cf8c139 100644
--- a/plugins/loudmouth/loudmouth-account.cpp
+++ b/plugins/loudmouth/loudmouth-account.cpp
@@ -359,7 +359,7 @@ LM::Account::edit ()
   xmlFree (xml_str);
 
   xml_str = xmlGetProp (node, BAD_CAST "password");
-  request->private_text ("password", _("Password:"), (const char*)xml_str, _("Password associated to the 
user"));
+  request->text ("password", _("Password:"), (const char*)xml_str, _("Password associated to the user"), 
Ekiga::FormVisitor::PASSWORD);
   xmlFree (xml_str);
 
   xml_str = xmlGetProp (node, BAD_CAST "startup");
@@ -392,7 +392,7 @@ LM::Account::on_edit_form_submitted (bool submitted,
   std::string server = result.text ("server");
   std::string port = result.text ("port");
   std::string resource = result.text ("resource");
-  std::string password = result.private_text ("password");
+  std::string password = result.text ("password");
   bool enable_on_startup = result.boolean ("enabled");
 
   xmlSetProp (node, BAD_CAST "name", BAD_CAST name.c_str ());
diff --git a/plugins/loudmouth/loudmouth-bank.cpp b/plugins/loudmouth/loudmouth-bank.cpp
index db1f74a..df1c0e2 100644
--- a/plugins/loudmouth/loudmouth-bank.cpp
+++ b/plugins/loudmouth/loudmouth-bank.cpp
@@ -121,7 +121,7 @@ LM::Bank::new_account ()
   request->text ("user", _("User:"), "", _("The user name, e.g. jim"));
   request->text ("server", _("Server:"), "", _("The server, e.g. jabber.org"));
   request->text ("resource", _("Resource:"), "", _("The resource, such as home or work, allowing to 
distinguish among several terminals registered to the same account; leave empty if you do not know what it 
is"));
-  request->private_text ("password", _("Password:"), "", _("Password associated to the user"));
+  request->text ("password", _("Password:"), "", _("Password associated to the user"), 
Ekiga::FormVisitor::PASSWORD);
   request->boolean ("enabled", _("Enable account"), true);
 
   questions (request);
@@ -138,7 +138,7 @@ LM::Bank::on_new_account_form_submitted (bool submitted,
   std::string user = result.text ("user");
   std::string server = result.text ("server");
   std::string resource = result.text ("resource");
-  std::string password = result.private_text ("password");
+  std::string password = result.text ("password");
   bool enable_on_startup = result.boolean ("enabled");
 
   boost::shared_ptr<Account> account (new Account (details, dialect, cluster,
diff --git a/plugins/resource-list/rl-cluster.cpp b/plugins/resource-list/rl-cluster.cpp
index cb9a15d..e1cf0d0 100644
--- a/plugins/resource-list/rl-cluster.cpp
+++ b/plugins/resource-list/rl-cluster.cpp
@@ -165,7 +165,7 @@ RL::Cluster::new_heap (const std::string name,
   request->text ("uri", _("Address:"), uri, std::string ());
   request->boolean ("writable", _("Writable:"), writable);
   request->text ("username", _("Username:"), username, std::string ());
-  request->private_text ("password", _("Password:"), password, std::string ());
+  request->text ("password", _("Password:"), password, std::string (), Ekiga::FormVisitor::PASSWORD);
   request->text ("user", _("User:"), user, std::string ());
 
   questions (request);
@@ -182,7 +182,7 @@ RL::Cluster::on_new_heap_form_submitted (bool submitted,
   const std::string name = result.text ("name");
   const std::string uri = result.text ("uri");
   const std::string username = result.text ("username");
-  const std::string password = result.private_text ("password");
+  const std::string password = result.text ("password");
   const std::string user = result.text ("user");
   bool writable = result.boolean ("writable");
 
diff --git a/plugins/resource-list/rl-heap.cpp b/plugins/resource-list/rl-heap.cpp
index f5cf582..a0444d5 100644
--- a/plugins/resource-list/rl-heap.cpp
+++ b/plugins/resource-list/rl-heap.cpp
@@ -470,7 +470,7 @@ RL::Heap::edit ()
   request->text ("user", _("Identifier:"), user_str, std::string ());
   request->boolean ("writable", _("Writable:"), writable);
   request->text ("username", _("Server username:"), username_str, std::string ());
-  request->private_text ("password", _("Server password:"), password_str, std::string ());
+  request->text ("password", _("Server password:"), password_str, std::string (), 
Ekiga::FormVisitor::PASSWORD);
 
   questions (request);
 }
@@ -487,7 +487,7 @@ RL::Heap::on_edit_form_submitted (bool submitted,
   std::string root_str = result.text ("root");
   std::string user_str = result.text ("user");
   std::string username_str = result.text ("username");
-  std::string password_str = result.private_text ("password");
+  std::string password_str = result.text ("password");
   bool writable = result.boolean ("writable");
 
   if (writable)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]