Updated the appearance of two warning dialogs.
[moonshot-ui.git] / src / moonshot-identity-management-view.vala
index 4c343a9..8033d75 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2011-2014, JANET(UK)
+ * Copyright (c) 2011-2016, JANET(UK)
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,7 +33,9 @@ using Gee;
 using Gtk;
 
 public class IdentityManagerView : Window {
 using Gtk;
 
 public class IdentityManagerView : Window {
-    private const int WINDOW_WIDTH = 400;
+    static MoonshotLogger logger = get_logger("IdentityManagerView");
+
+    private const int WINDOW_WIDTH = 700;
     private const int WINDOW_HEIGHT = 500;
     protected IdentityManagerApp parent_app;
     #if OS_MACOS
     private const int WINDOW_HEIGHT = 500;
     protected IdentityManagerApp parent_app;
     #if OS_MACOS
@@ -42,29 +44,22 @@ public class IdentityManagerView : Window {
     private UIManager ui_manager = new UIManager();
     private Entry search_entry;
     private VBox vbox_right;
     private UIManager ui_manager = new UIManager();
     private Entry search_entry;
     private VBox vbox_right;
-    private VBox login_vbox;
-    private VBox services_vbox;
     private CustomVBox custom_vbox;
     private CustomVBox custom_vbox;
-    private VBox services_internal_vbox;
-
-    private Entry issuer_entry;
-    private Entry username_entry;
-    private Entry password_entry;
-    private Label prompting_service;
+    private VBox service_prompt_vbox;
     private Label no_identity_title;
     private Label no_identity_title;
-    private CheckButton remember_checkbutton;
-    private Button update_password_button;
+    private Button edit_button;
+    private Button remove_button;
 
 
+    private Button send_button;
+    
     private Gtk.ListStore* listmodel;
     private TreeModelFilter filter;
 
     private Gtk.ListStore* listmodel;
     private TreeModelFilter filter;
 
-    public IdentityManagerModel identities_manager;
+    internal IdentityManagerModel identities_manager;
     private unowned SList<IdCard>    candidates;
 
     public GLib.Queue<IdentityRequest> request_queue;
 
     private unowned SList<IdCard>    candidates;
 
     public GLib.Queue<IdentityRequest> request_queue;
 
-    private HashTable<Gtk.Button, string> service_button_map;
-
     private enum Columns
     {
         IDCARD_COL,
     private enum Columns
     {
         IDCARD_COL,
@@ -75,14 +70,8 @@ public class IdentityManagerView : Window {
         N_COLUMNS
     }
 
         N_COLUMNS
     }
 
-    private const string layout =
+    private const string menu_layout =
     "<menubar name='MenuBar'>" +
     "<menubar name='MenuBar'>" +
-    "        <menu name='FileMenu' action='FileMenuAction'>" +
-    "            <menuitem name='AddIdCard' action='AddIdCardAction' />" +
-    "            <separator />" +
-    "            <menuitem name='Quit' action='QuitAction' />" +
-    "        </menu>" +
-    "" +
     "        <menu name='HelpMenu' action='HelpMenuAction'>" +
     "             <menuitem name='About' action='AboutAction' />" +
     "        </menu>" +
     "        <menu name='HelpMenu' action='HelpMenuAction'>" +
     "             <menuitem name='About' action='AboutAction' />" +
     "        </menu>" +
@@ -95,7 +84,6 @@ public class IdentityManagerView : Window {
         #endif
         identities_manager = parent_app.model;
         request_queue = new GLib.Queue<IdentityRequest>();
         #endif
         identities_manager = parent_app.model;
         request_queue = new GLib.Queue<IdentityRequest>();
-        service_button_map = new HashTable<Gtk.Button, string>(direct_hash, direct_equal);
         this.title = "Moonshot Identity Selector";
         this.set_position(WindowPosition.CENTER);
         set_default_size(WINDOW_WIDTH, WINDOW_HEIGHT);
         this.title = "Moonshot Identity Selector";
         this.set_position(WindowPosition.CENTER);
         set_default_size(WINDOW_WIDTH, WINDOW_HEIGHT);
@@ -177,11 +165,11 @@ public class IdentityManagerView : Window {
 
     private void setup_list_model()
     {
 
     private void setup_list_model()
     {
-        this.listmodel = new Gtk.ListStore (Columns.N_COLUMNS, typeof(IdCard),
-                                            typeof(Gdk.Pixbuf),
-                                            typeof(string),
-                                            typeof(string),
-                                            typeof(string));
+        this.listmodel = new Gtk.ListStore(Columns.N_COLUMNS, typeof(IdCard),
+                                           typeof(Gdk.Pixbuf),
+                                           typeof(string),
+                                           typeof(string),
+                                           typeof(string));
         this.filter = new TreeModelFilter(listmodel, null);
 
         filter.set_visible_func(visible_func);
         this.filter = new TreeModelFilter(listmodel, null);
 
         filter.set_visible_func(visible_func);
@@ -207,8 +195,6 @@ public class IdentityManagerView : Window {
         var has_text = this.search_entry.get_text_length() > 0;
         this.search_entry.set_icon_sensitive(EntryIconPosition.PRIMARY, has_text);
         this.search_entry.set_icon_sensitive(EntryIconPosition.SECONDARY, has_text);
         var has_text = this.search_entry.get_text_length() > 0;
         this.search_entry.set_icon_sensitive(EntryIconPosition.PRIMARY, has_text);
         this.search_entry.set_icon_sensitive(EntryIconPosition.SECONDARY, has_text);
-
-        this.vbox_right.set_visible(false);
     }
 
     private bool search_entry_key_press_event_cb(Gdk.EventKey e)
     }
 
     private bool search_entry_key_press_event_cb(Gdk.EventKey e)
@@ -221,38 +207,17 @@ public class IdentityManagerView : Window {
         return false;
     }
 
         return false;
     }
 
-    private void update_password_cb()
-    {
-        if (this.custom_vbox.current_idcard != null) {
-            var identity = this.custom_vbox.current_idcard.id_card;
-            var dialog = new AddPasswordDialog(identity, null);
-            var result = dialog.run();
-
-            switch (result) {
-            case ResponseType.OK:
-                identity.password = dialog.password;
-                identity.store_password = dialog.remember;
-                if (dialog.remember)
-                    identity.temporary = false;
-                identity = identities_manager.update_card(identity);
-                break;
-            default:
-                break;
-            }
-            dialog.destroy();
-        }
-    }
-
     private void load_id_cards() {
     private void load_id_cards() {
+        logger.trace("load_id_cards");
+
         string current_idcard_nai = null;
         if (this.custom_vbox.current_idcard != null) {
             current_idcard_nai = custom_vbox.current_idcard.id_card.nai;
             custom_vbox.current_idcard = null;
         }
         var children = this.custom_vbox.get_children();
         string current_idcard_nai = null;
         if (this.custom_vbox.current_idcard != null) {
             current_idcard_nai = custom_vbox.current_idcard.id_card.nai;
             custom_vbox.current_idcard = null;
         }
         var children = this.custom_vbox.get_children();
-        foreach (var id_card_widget in children) {
-            remove_id_card_widget((IdCardWidget)id_card_widget);
-        }   
+
+        custom_vbox.clear();
         this.listmodel->clear();
         LinkedList<IdCard> card_list = identities_manager.get_card_list() ;
         if (card_list == null) {
         this.listmodel->clear();
         LinkedList<IdCard> card_list = identities_manager.get_card_list() ;
         if (card_list == null) {
@@ -263,67 +228,20 @@ public class IdentityManagerView : Window {
             add_id_card_data(id_card);
             IdCardWidget id_card_widget = add_id_card_widget(id_card);
             if (id_card_widget.id_card.nai == current_idcard_nai) {
             add_id_card_data(id_card);
             IdCardWidget id_card_widget = add_id_card_widget(id_card);
             if (id_card_widget.id_card.nai == current_idcard_nai) {
-                fill_details(id_card_widget);
+                // fill_details(id_card_widget.id_card);
                 id_card_widget.expand();
             }
         }
                 id_card_widget.expand();
             }
         }
-        if (custom_vbox.current_idcard == null)
-            fill_details(null);
     }
     
     }
     
-    private void fill_details(IdCardWidget? id_card_widget)
-    {
-        var vr_children = this.vbox_right.get_children();
-        foreach (var vr_child in vr_children) {
-            this.vbox_right.remove(vr_child);
-        }
-        if (id_card_widget != null) {
-            var id_card = id_card_widget.id_card;
-            if (id_card.display_name == IdCard.NO_IDENTITY) {
-                this.vbox_right.pack_start(no_identity_title, false, true, 0);
-            } else {
-                this.issuer_entry.set_text(id_card.issuer);
-                this.username_entry.set_text(id_card.username);
-                this.password_entry.set_text(id_card.password ?? "");
-                this.vbox_right.pack_start(login_vbox, false, true, 0);
-                this.remember_checkbutton.active = id_card.store_password;
-            }
-            this.vbox_right.pack_start(services_vbox, false, true, 0);
-
-            var children = this.services_internal_vbox.get_children();
-            foreach (var hbox in children) {
-                services_internal_vbox.remove(hbox);
-            }
-            fill_services_vbox(id_card_widget.id_card);
-        }
-    }
-
-    private void show_details(IdCard id_card)
-    {
-        this.vbox_right.set_visible(!vbox_right.get_visible());
-
-        if (this.vbox_right.get_visible() == false)
-        {
-            this.resize(WINDOW_WIDTH, WINDOW_HEIGHT);
-        }
-    }
-
-    private void details_identity_cb(IdCardWidget id_card_widget)
-    {
-        fill_details(id_card_widget);
-        show_details(id_card_widget.id_card);
-    }
-
-    private IdCard get_id_card_data(AddIdentityDialog dialog)
+    private IdCard update_id_card_data(IdentityDialog dialog, IdCard id_card)
     {
     {
-        var id_card = new IdCard();
-
         id_card.display_name = dialog.display_name;
         id_card.issuer = dialog.issuer;
         id_card.username = dialog.username;
         id_card.password = dialog.password;
         id_card.store_password = dialog.store_password;
         id_card.display_name = dialog.display_name;
         id_card.issuer = dialog.issuer;
         id_card.username = dialog.username;
         id_card.password = dialog.password;
         id_card.store_password = dialog.store_password;
-        id_card.services = {};
+        id_card.services = dialog.get_services();
 
         return id_card;
     }
 
         return id_card;
     }
@@ -368,14 +286,20 @@ public class IdentityManagerView : Window {
     {
         var id_card_widget = new IdCardWidget(id_card);
         this.custom_vbox.add_id_card_widget(id_card_widget);
     {
         var id_card_widget = new IdCardWidget(id_card);
         this.custom_vbox.add_id_card_widget(id_card_widget);
-        id_card_widget.details_id.connect(details_identity_cb);
-        id_card_widget.remove_id.connect(remove_identity_cb);
-        id_card_widget.send_id.connect((w) => send_identity_cb(w.id_card));
-        id_card_widget.expanded.connect(this.custom_vbox.receive_expanded_event);
-        id_card_widget.expanded.connect(fill_details);
+        id_card_widget.expanded.connect(this.widget_selected_cb);
         return id_card_widget;
     }
 
         return id_card_widget;
     }
 
+    private void widget_selected_cb(IdCardWidget id_card_widget)
+    {
+        this.remove_button.set_sensitive(true);
+        this.edit_button.set_sensitive(true);
+        this.custom_vbox.receive_expanded_event(id_card_widget);
+
+        if (this.request_queue.length > 0)
+             this.send_button.set_sensitive(true);
+    }
+
     public bool add_identity(IdCard id_card, bool force_flat_file_store)
     {
         #if OS_MACOS
     public bool add_identity(IdCard id_card, bool force_flat_file_store)
     {
         #if OS_MACOS
@@ -387,8 +311,10 @@ public class IdentityManagerView : Window {
         #else
         Gtk.MessageDialog dialog;
         IdCard? prev_id = identities_manager.find_id_card(id_card.nai, force_flat_file_store);
         #else
         Gtk.MessageDialog dialog;
         IdCard? prev_id = identities_manager.find_id_card(id_card.nai, force_flat_file_store);
+        logger.trace("add_identity: find_id_card returned " + (prev_id != null ? "non-null" : "null"));
         if (prev_id!=null) {
             int flags = prev_id.Compare(id_card);
         if (prev_id!=null) {
             int flags = prev_id.Compare(id_card);
+            logger.trace("add_identity: compare returned " + flags.to_string());
             if (flags == 0) {
                 return false; // no changes, no need to update
             } else if ((flags & (1 << IdCard.DiffFlags.DISPLAY_NAME)) != 0) {
             if (flags == 0) {
                 return false; // no changes, no need to update
             } else if ((flags & (1 << IdCard.DiffFlags.DISPLAY_NAME)) != 0) {
@@ -428,16 +354,16 @@ public class IdentityManagerView : Window {
         return false;
     }
 
         return false;
     }
 
-    private void add_identity_manual_cb()
+    private void add_identity_cb()
     {
     {
-        var dialog = new AddIdentityDialog();
+        var dialog = new IdentityDialog(this);
         int result = ResponseType.CANCEL;
         while (!dialog.complete)
             result = dialog.run();
 
         switch (result) {
         case ResponseType.OK:
         int result = ResponseType.CANCEL;
         while (!dialog.complete)
             result = dialog.run();
 
         switch (result) {
         case ResponseType.OK:
-            this.identities_manager.add_card(get_id_card_data(dialog), false);
+            this.identities_manager.add_card(update_id_card_data(dialog, new IdCard()), false);
             break;
         default:
             break;
             break;
         default:
             break;
@@ -445,27 +371,45 @@ public class IdentityManagerView : Window {
         dialog.destroy();
     }
 
         dialog.destroy();
     }
 
-    private void remove_id_card_widget(IdCardWidget id_card_widget) {
-        this.custom_vbox.remove_id_card_widget(id_card_widget);
+    private void edit_identity_cb(IdCard card)
+    {
+        var dialog = new IdentityDialog.with_idcard(card, _("Edit Identity"), this);
+        int result = ResponseType.CANCEL;
+        while (!dialog.complete)
+            result = dialog.run();
+
+        switch (result) {
+        case ResponseType.OK:
+            this.identities_manager.update_card(update_id_card_data(dialog, card));
+            break;
+        default:
+            break;
+        }
+        dialog.destroy();
     }
 
     private void remove_identity(IdCardWidget id_card_widget)
     {
         var id_card = id_card_widget.id_card;
     }
 
     private void remove_identity(IdCardWidget id_card_widget)
     {
         var id_card = id_card_widget.id_card;
-        remove_id_card_widget(id_card_widget);
+        this.custom_vbox.remove_id_card_widget(id_card_widget);
 
         this.identities_manager.remove_card(id_card);
 
         this.identities_manager.remove_card(id_card);
+
+        // Nothing is selected, so disable buttons
+        this.edit_button.set_sensitive(false);
+        this.remove_button.set_sensitive(false);
+        this.send_button.set_sensitive(false);
     }
 
     private void redraw_id_card_widgets()
     {
     }
 
     private void redraw_id_card_widgets()
     {
+        logger.trace("redraw_id_card_widgets");
+
         TreeIter iter;
         IdCard id_card;
 
         var children = this.custom_vbox.get_children();
         TreeIter iter;
         IdCard id_card;
 
         var children = this.custom_vbox.get_children();
-        foreach (var id_card_widget in children) {
-            remove_id_card_widget((IdCardWidget )id_card_widget); //id_card_widget.destroy();
-        }
+        this.custom_vbox.clear();
 
         if (filter.get_iter_first(out iter))
         {
 
         if (filter.get_iter_first(out iter))
         {
@@ -484,27 +428,43 @@ public class IdentityManagerView : Window {
     {
         var id_card = id_card_widget.id_card;
 
     {
         var id_card = id_card_widget.id_card;
 
-        var dialog = new MessageDialog(this,
-                                       DialogFlags.DESTROY_WITH_PARENT,
-                                       MessageType.QUESTION,
-                                       Gtk.ButtonsType.YES_NO,
-                                       _("Are you sure you want to delete %s ID Card?"), id_card.issuer);
-        var result = dialog.run();
-        switch (result) {
-        case ResponseType.YES:
+        bool remove = WarningDialog.confirm(this, 
+                                            "<span font-weight='heavy'>You are about to remove the identity '%s'.</span>"
+                                            .printf(id_card.display_name)
+                                            + "\n\nAre you sure you want to do this?",
+                                            "delete_idcard");
+        if (remove) 
             remove_identity(id_card_widget);
             remove_identity(id_card_widget);
-            break;
-        default:
-            break;
-        }
-        dialog.destroy();
     }
 
     }
 
-    public void set_prompting_service(string service)
+    private void set_prompting_service(string service)
+    {
+        clear_selection_prompts();
+
+        var prompting_service = new Label(_("Identity requested for service:\n%s").printf(service));
+        prompting_service.set_line_wrap(true);
+
+        // left-align
+        prompting_service.set_alignment(0, (float )0.5);
+
+        var selection_prompt = new Label(_("Select your identity:"));
+        selection_prompt.set_alignment(0, 1);
+
+        this.service_prompt_vbox.pack_start(prompting_service, false, false, 12);
+        this.service_prompt_vbox.pack_start(selection_prompt, false, false, 2);
+        this.service_prompt_vbox.show_all();
+    }
+
+    private void clear_selection_prompts()
     {
     {
-        prompting_service.set_label( _("Identity requested for service: %s").printf(service) );
+        var list = service_prompt_vbox.get_children();
+        foreach (Widget w in list)
+        {
+            service_prompt_vbox.remove(w);
+        }
     }
 
     }
 
+
     public void queue_identity_request(IdentityRequest request)
     {
         if (this.request_queue.is_empty())
     public void queue_identity_request(IdentityRequest request)
     {
         if (this.request_queue.is_empty())
@@ -564,10 +524,10 @@ public class IdentityManagerView : Window {
         return retval;
     }
 
         return retval;
     }
 
-    public void send_identity_cb(IdCard id)
+    private void send_identity_cb(IdCard id)
     {
         IdCard identity = id;
     {
         IdCard identity = id;
-        return_if_fail (request_queue.length > 0);
+        return_if_fail(request_queue.length > 0);
 
         candidates = null;
         var request = this.request_queue.pop_head();
 
         candidates = null;
         var request = this.request_queue.pop_head();
@@ -575,7 +535,7 @@ public class IdentityManagerView : Window {
         if (this.request_queue.is_empty())
         {
             candidates = null;
         if (this.request_queue.is_empty())
         {
             candidates = null;
-            prompting_service.set_label(_(""));
+            clear_selection_prompts();
             if (!parent_app.explicitly_launched) {
 // The following occasionally causes the app to exit without sending the dbus
 // reply, so for now we just don't exit
             if (!parent_app.explicitly_launched) {
 // The following occasionally causes the app to exit without sending the dbus
 // reply, so for now we just don't exit
@@ -597,105 +557,27 @@ public class IdentityManagerView : Window {
         request.return_identity(identity);
     }
 
         request.return_identity(identity);
     }
 
-    private void label_make_bold(Label label)
-    {
-        var font_desc = new Pango.FontDescription();
-
-        font_desc.set_weight(Pango.Weight.BOLD);
-
-        /* This will only affect the weight of the font, the rest is
-         * from the current state of the widget, which comes from the
-         * theme or user prefs, since the font desc only has the
-         * weight flag turned on.
-         */
-        label.modify_font(font_desc);
-    }
-
-    private void fill_services_vbox(IdCard id_card)
-    {
-        int i = 0;
-        var n_columns = id_card.services.length;
+    // private void label_make_bold(Label label)
+    // {
+    //     var font_desc = new Pango.FontDescription();
 
 
-        var services_table = new Table(n_columns, 2, false);
-        services_table.set_col_spacings(10);
-        services_table.set_row_spacings(10);
-        this.services_internal_vbox.add(services_table);
-        
-        service_button_map.remove_all();
+    //     font_desc.set_weight(Pango.Weight.BOLD);
 
 
-        foreach (string service in id_card.services)
-        {
-            var label = new Label(service);
-            label.set_alignment(0, (float) 0.5);
-            #if VALA_0_12
-                var remove_button = new Button.from_stock(Stock.REMOVE);
-            #else
-                var remove_button = new Button.from_stock(STOCK_REMOVE);
-            #endif
-
-
-            service_button_map.insert(remove_button, service);
-            
-            remove_button.clicked.connect((remove_button) =>
-                {
-                    var candidate = service_button_map.lookup(remove_button);
-                    if (candidate == null)
-                        return;
-                    var dialog = new Gtk.MessageDialog(this,
-                                                       Gtk.DialogFlags.DESTROY_WITH_PARENT,
-                                                       Gtk.MessageType.QUESTION,
-                                                       Gtk.ButtonsType.YES_NO,
-                                                       _("Are you sure you want to stop '%s' ID Card from being used with %s?"),
-                                                       custom_vbox.current_idcard.id_card.display_name,
-                                                       candidate);
-                    var ret = dialog.run();
-                    dialog.hide();
-              
-                    if (ret == Gtk.ResponseType.YES)
-                    {
-                        IdCard idcard = custom_vbox.current_idcard.id_card;
-                        if (idcard != null) {
-                            SList<string> services = new SList<string>();
-                
-                            foreach (string srv in idcard.services)
-                            {
-                                if (srv == candidate)
-                                    continue;
-                                services.append(srv);
-                            }
-                
-                            idcard.services = new string[services.length()];
-                            for (int j = 0; j < idcard.services.length; j++)
-                            {
-                                idcard.services[j] = services.nth_data(j);
-                            }
-                
-                            identities_manager.update_card(idcard);
-                        }
-                    }
-              
-                });
-            services_table.attach_defaults(label, 0, 1, i, i+1);
-            services_table.attach_defaults(remove_button, 1, 2, i, i+1);
-            i++;
-        }
-        this.services_internal_vbox.show_all();
-    }
+    //     /* This will only affect the weight of the font, the rest is
+    //      * from the current state of the widget, which comes from the
+    //      * theme or user prefs, since the font desc only has the
+    //      * weight flag turned on.
+    //      */
+    //     label.modify_font(font_desc);
+    // }
 
     private void on_about_action()
     {
 
     private void on_about_action()
     {
-        string[] authors = {
-            "Javier Jardón <jjardon@codethink.co.uk>",
-            "Sam Thursfield <samthursfield@codethink.co.uk>",
-            "Alberto Ruiz <alberto.ruiz@codethink.co.uk>",
-            null
-        };
-
-        string copyright = "Copyright 2011 JANET";
+        string copyright = "Copyright 2011, 2016 JANET";
 
         string license =
         """
 
         string license =
         """
-Copyright (c) 2011, JANET(UK)
+Copyright (c) 2011, 2016 JANET(UK)
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -733,7 +615,6 @@ SUCH DAMAGE.
                               "version", Config.PACKAGE_VERSION,
                               "license", license,
                               "website-label", _("Visit the Moonshot project web site"),
                               "version", Config.PACKAGE_VERSION,
                               "license", license,
                               "website-label", _("Visit the Moonshot project web site"),
-                              "authors", authors,
                               "translator-credits", _("translator-credits"),
                               null
             );
                               "translator-credits", _("translator-credits"),
                               null
             );
@@ -742,34 +623,6 @@ SUCH DAMAGE.
     private Gtk.ActionEntry[] create_actions() {
         Gtk.ActionEntry[] actions = new Gtk.ActionEntry[0];
 
     private Gtk.ActionEntry[] create_actions() {
         Gtk.ActionEntry[] actions = new Gtk.ActionEntry[0];
 
-        Gtk.ActionEntry filemenu = { "FileMenuAction",
-                                     null,
-                                     N_("_File"),
-                                     null, null, null };
-        actions += filemenu;
-        Gtk.ActionEntry add = { "AddIdCardAction",
-                                #if VALA_0_12
-                                Stock.ADD,
-                                #else
-                                STOCK_ADD,
-                                #endif
-                                N_("Add ID Card"),
-                                null,
-                                N_("Add a new ID Card"),
-                                add_identity_manual_cb };
-        actions += add;
-        Gtk.ActionEntry quit = { "QuitAction",
-                                 #if VALA_0_12
-                                 Stock.QUIT,
-                                 #else
-                                 STOCK_QUIT,
-                                 #endif
-                                 N_("Quit"),
-                                 "<control>Q",
-                                 N_("Quit the application"),
-                                 Gtk.main_quit };
-        actions += quit;
-
         Gtk.ActionEntry helpmenu = { "HelpMenuAction",
                                      null,
                                      N_("_Help"),
         Gtk.ActionEntry helpmenu = { "HelpMenuAction",
                                      null,
                                      N_("_Help"),
@@ -798,17 +651,23 @@ SUCH DAMAGE.
         ui_manager.insert_action_group(action_group, 0);
         try
         {
         ui_manager.insert_action_group(action_group, 0);
         try
         {
-            ui_manager.add_ui_from_string(layout, -1);
+            ui_manager.add_ui_from_string(menu_layout, -1);
         }
         catch (Error e)
         {
             stderr.printf("%s\n", e.message);
         }
         catch (Error e)
         {
             stderr.printf("%s\n", e.message);
+            logger.error("create_ui_manager: Caught error: " + e.message);
         }
         ui_manager.ensure_update();
     }
 
     private void build_ui()
     {
         }
         ui_manager.ensure_update();
     }
 
     private void build_ui()
     {
+        // Note: On Debian7/Gtk+2, the menu bar remains gray. This doesn't happen on Debian8/Gtk+3.
+        Gdk.Color white = Gdk.Color();
+        white.red = white.green = white.blue = 65535;
+        this.modify_bg(StateType.NORMAL, white);
+
         create_ui_manager();
 
         this.search_entry = new Entry();
         create_ui_manager();
 
         this.search_entry = new Entry();
@@ -816,14 +675,12 @@ SUCH DAMAGE.
         set_atk_name_description(search_entry, _("Search entry"), _("Search for a specific ID Card"));
         this.search_entry.set_icon_from_pixbuf(EntryIconPosition.PRIMARY,
                                                find_icon_sized("edit-find", Gtk.IconSize.MENU));
         set_atk_name_description(search_entry, _("Search entry"), _("Search for a specific ID Card"));
         this.search_entry.set_icon_from_pixbuf(EntryIconPosition.PRIMARY,
                                                find_icon_sized("edit-find", Gtk.IconSize.MENU));
-//                                                find_icon_sized("edit-find-symbolic", Gtk.IconSize.MENU));
         this.search_entry.set_icon_tooltip_text(EntryIconPosition.PRIMARY,
         this.search_entry.set_icon_tooltip_text(EntryIconPosition.PRIMARY,
-                                                _("Search identity or service"));
+                                                _("Search for an identity or service"));
         this.search_entry.set_icon_sensitive(EntryIconPosition.PRIMARY, false);
 
         this.search_entry.set_icon_from_pixbuf(EntryIconPosition.SECONDARY,
                                                find_icon_sized("process-stop", Gtk.IconSize.MENU));
         this.search_entry.set_icon_sensitive(EntryIconPosition.PRIMARY, false);
 
         this.search_entry.set_icon_from_pixbuf(EntryIconPosition.SECONDARY,
                                                find_icon_sized("process-stop", Gtk.IconSize.MENU));
-//                                                find_icon_sized("edit-clear-symbolic", Gtk.IconSize.MENU));
         this.search_entry.set_icon_tooltip_text(EntryIconPosition.SECONDARY,
                                                 _("Clear the current search"));
         this.search_entry.set_icon_sensitive(EntryIconPosition.SECONDARY, false);
         this.search_entry.set_icon_tooltip_text(EntryIconPosition.SECONDARY,
                                                 _("Clear the current search"));
         this.search_entry.set_icon_sensitive(EntryIconPosition.SECONDARY, false);
@@ -832,25 +689,47 @@ SUCH DAMAGE.
         this.search_entry.icon_press.connect(search_entry_icon_press_cb);
         this.search_entry.notify["text"].connect(search_entry_text_changed_cb);
         this.search_entry.key_press_event.connect(search_entry_key_press_event_cb);
         this.search_entry.icon_press.connect(search_entry_icon_press_cb);
         this.search_entry.notify["text"].connect(search_entry_text_changed_cb);
         this.search_entry.key_press_event.connect(search_entry_key_press_event_cb);
+        this.search_entry.set_width_chars(30);
+
 
 
-        this.custom_vbox = new CustomVBox(this, false, 6);
+        this.custom_vbox = new CustomVBox(this, false, 2);
 
         var viewport = new Viewport(null, null);
 
         var viewport = new Viewport(null, null);
-        viewport.set_border_width(6);
+        viewport.set_border_width(2);
         viewport.set_shadow_type(ShadowType.NONE);
         viewport.add(custom_vbox);
         viewport.set_shadow_type(ShadowType.NONE);
         viewport.add(custom_vbox);
-        var scroll = new ScrolledWindow(null, null);
-        scroll.set_policy(PolicyType.NEVER, PolicyType.AUTOMATIC);
-        scroll.set_shadow_type(ShadowType.IN);
-        scroll.add_with_viewport(viewport);
-        this.prompting_service = new Label(_(""));
-        // left-align
-        prompting_service.set_alignment(0, (float )0.5);
+        var id_scrollwin = new ScrolledWindow(null, null);
+        id_scrollwin.set_policy(PolicyType.NEVER, PolicyType.AUTOMATIC);
+        id_scrollwin.set_shadow_type(ShadowType.IN);
+        id_scrollwin.add_with_viewport(viewport);
+
+        service_prompt_vbox = new VBox(false, 0);
 
         var vbox_left = new VBox(false, 0);
 
         var vbox_left = new VBox(false, 0);
-        vbox_left.pack_start(search_entry, false, false, 6);
-        vbox_left.pack_start(scroll, true, true, 0);
-        vbox_left.pack_start(prompting_service, false, false, 6);
+        vbox_left.pack_start(service_prompt_vbox, false, false, 12);
+
+        var search_hbox = new HBox(false, 6);
+        search_hbox.pack_end(search_entry, false, false, 0);
+        //// var search_label = new Label(_("Search:"));
+        //// search_label.set_alignment(1, (float) 0.5);
+        //// set_atk_relation(search_label, search_entry, Atk.RelationType.LABEL_FOR);
+        //// search_hbox.pack_end(search_label, false, false, 6);
+
+        var full_search_label = new Label(_("Search for an identity or service"));
+        full_search_label.set_alignment(1, 0);
+        var search_vbox = new VBox(false, 4);
+        search_vbox.pack_start(full_search_label, false, false, 0);
+        search_vbox.pack_start(search_hbox, false, false, 0);
+
+        var inner_left_vbox = new VBox(false, 6);
+        inner_left_vbox.pack_start(search_vbox, false, false, 6);
+//        inner_left_vbox.pack_start(selection_prompt, false, false, 6);
+        inner_left_vbox.pack_start(id_scrollwin, true, true, 0);
+
+        var id_and_button_box = new HBox(false, 6);
+        id_and_button_box.pack_start(inner_left_vbox, true, true, 6);
+        vbox_left.pack_start(id_and_button_box, true, true, 0);
+        // vbox_left.pack_start(prompting_service, false, false, 6);
         vbox_left.set_size_request(WINDOW_WIDTH, 0);
 
         this.no_identity_title = new Label(_("No Identity: Send this identity to services which should not use Moonshot"));
         vbox_left.set_size_request(WINDOW_WIDTH, 0);
 
         this.no_identity_title = new Label(_("No Identity: Send this identity to services which should not use Moonshot"));
@@ -858,90 +737,59 @@ SUCH DAMAGE.
         no_identity_title.set_line_wrap(true);
         no_identity_title.show();
 
         no_identity_title.set_line_wrap(true);
         no_identity_title.show();
 
-        var login_vbox_title = new Label(_("Login: "));
-        label_make_bold(login_vbox_title);
-        login_vbox_title.set_alignment(0, (float) 0.5);
-        var issuer_label = new Label(_("Issuer:"));
-        issuer_label.set_alignment(1, (float) 0.5);
-        this.issuer_entry = new Entry();
-        issuer_entry.set_can_focus(false);
-        var username_label = new Label(_("Username:"));
-        username_label.set_alignment(1, (float) 0.5);
-        this.username_entry = new Entry();
-        username_entry.set_can_focus(false);
-        var password_label = new Label(_("Password:"));
-        password_label.set_alignment(1, (float) 0.5);
-        this.password_entry = new Entry();
-        password_entry.set_invisible_char('*');
-        password_entry.set_visibility(false);
-        password_entry.set_sensitive(false);
-        this.remember_checkbutton = new CheckButton.with_label(_("Remember password"));
-        remember_checkbutton.set_sensitive(false);
-        this.update_password_button = new Button.with_label(_("Update Password"));
-        this.update_password_button.clicked.connect(update_password_cb);
-
-        set_atk_relation(issuer_label, issuer_entry, Atk.RelationType.LABEL_FOR);
-        set_atk_relation(username_label, username_entry, Atk.RelationType.LABEL_FOR);
-        set_atk_relation(password_entry, password_entry, Atk.RelationType.LABEL_FOR);
-
-        var login_table = new Table(5, 2, false);
-        login_table.set_col_spacings(10);
-        login_table.set_row_spacings(10);
-        login_table.attach_defaults(issuer_label, 0, 1, 0, 1);
-        login_table.attach_defaults(issuer_entry, 1, 2, 0, 1);
-        login_table.attach_defaults(username_label, 0, 1, 1, 2);
-        login_table.attach_defaults(username_entry, 1, 2, 1, 2);
-        login_table.attach_defaults(password_label, 0, 1, 2, 3);
-        login_table.attach_defaults(password_entry, 1, 2, 2, 3);
-        login_table.attach_defaults(remember_checkbutton,  1, 2, 3, 4);
-        login_table.attach_defaults(update_password_button, 0, 1, 4, 5);
-        var login_vbox_alignment = new Alignment(0, 0, 0, 0);
-        login_vbox_alignment.set_padding(0, 0, 12, 0);
-        login_vbox_alignment.add(login_table);
-        this.login_vbox = new VBox(false, 6);
-        login_vbox.pack_start(login_vbox_title, false, true, 0);
-        login_vbox.pack_start(login_vbox_alignment, false, true, 0);
-
-        var services_vbox_title = new Label(_("Services:"));
-        label_make_bold(services_vbox_title);
-        services_vbox_title.set_alignment(0, (float) 0.5);
-        var services_vbox_alignment = new Alignment(0, 0, 0, 0);
-        services_vbox_alignment.set_padding(0, 0, 12, 0);
-        this.services_internal_vbox = new VBox(true, 6);
-        services_vbox_alignment.add(services_internal_vbox);
-        this.services_vbox = new VBox(false, 6);
-        services_vbox.pack_start(services_vbox_title, false, true, 0);
-        services_vbox.pack_start(services_vbox_alignment, false, true, 0);
-
-        this.vbox_right = new VBox(false, 18);
-        vbox_right.pack_start(login_vbox, false, true, 0);
-        vbox_right.pack_start(services_vbox, false, true, 0);
-
-        var hbox = new HBox(false, 12);
-        hbox.pack_start(vbox_left, false, false, 0);
-        hbox.pack_start(vbox_right, true, true, 0);
+        this.vbox_right = new VBox(false, 6);
+
+        var add_button = new Button.with_label(_("Add"));
+        add_button.clicked.connect((w) => {add_identity_cb();});
+
+        this.edit_button = new Button.with_label(_("Edit"));
+        edit_button.clicked.connect((w) => {edit_identity_cb(custom_vbox.current_idcard.id_card);});
+        edit_button.set_sensitive(false);
+
+        this.remove_button = new Button.with_label(_("Remove"));
+        remove_button.clicked.connect((w) => {remove_identity_cb(custom_vbox.current_idcard);});
+        remove_button.set_sensitive(false);
+
+        send_button = new Button.with_label(_("Send"));
+        send_button.clicked.connect((w) => {send_identity_cb(custom_vbox.current_idcard.id_card);});
+        // send_button.set_visible(false);
+        send_button.set_sensitive(false);
+
+        var empty_box = new VBox(false, 0);
+        empty_box.set_size_request(0, 0);
+        vbox_right.pack_start(empty_box, false, false, 14);
+        vbox_right.pack_start(add_button, false, false, 6);
+        vbox_right.pack_start(edit_button, false, false, 6);
+        vbox_right.pack_start(remove_button, false, false, 6);
+        vbox_right.pack_start(send_button, false, false, 24);
+
+        id_and_button_box.pack_start(vbox_right, false, false, 0);
 
         var main_vbox = new VBox(false, 0);
 
         var main_vbox = new VBox(false, 0);
+
+        // Note: This places a border above the menubar. Is that what we want?
         main_vbox.set_border_width(12);
         main_vbox.set_border_width(12);
-        #if OS_MACOS
+
+#if OS_MACOS
         // hide the  File | Quit menu item which is now on the Mac Menu
         // hide the  File | Quit menu item which is now on the Mac Menu
-        Gtk.Widget quit_item =  this.ui_manager.get_widget("/MenuBar/FileMenu/Quit");
-        quit_item.hide();
+//        Gtk.Widget quit_item =  this.ui_manager.get_widget("/MenuBar/FileMenu/Quit");
+//        quit_item.hide();
         
         Gtk.MenuShell menushell = this.ui_manager.get_widget("/MenuBar") as Gtk.MenuShell;
         
         Gtk.MenuShell menushell = this.ui_manager.get_widget("/MenuBar") as Gtk.MenuShell;
+        menushell.modify_bg(StateType.NORMAL, white);
+
         osxApp.set_menu_bar(menushell);
         osxApp.set_use_quartz_accelerators(true);
         osxApp.sync_menu_bar();
         osxApp.set_menu_bar(menushell);
         osxApp.set_use_quartz_accelerators(true);
         osxApp.sync_menu_bar();
-        osxApp.ready(); 
-        #else
+        osxApp.ready();
+#else
         var menubar = this.ui_manager.get_widget("/MenuBar");
         main_vbox.pack_start(menubar, false, false, 0);
         var menubar = this.ui_manager.get_widget("/MenuBar");
         main_vbox.pack_start(menubar, false, false, 0);
-        #endif
-        main_vbox.pack_start(hbox, true, true, 0);
+        menubar.modify_bg(StateType.NORMAL, white);
+#endif
+        main_vbox.pack_start(vbox_left, true, true, 0);
         add(main_vbox);
         main_vbox.show_all();
         add(main_vbox);
         main_vbox.show_all();
-        this.vbox_right.hide();
     } 
 
     private void set_atk_name_description(Widget widget, string name, string description)
     } 
 
     private void set_atk_name_description(Widget widget, string name, string description)
@@ -966,5 +814,3 @@ SUCH DAMAGE.
         atk_widget.add_relationship(relationship, atk_target_widget);
     }
 }
         atk_widget.add_relationship(relationship, atk_target_widget);
     }
 }
-
-