d7c6194b07a00f543acde19fa19ad09d9b647a96
[moonshot-ui.git] / src / moonshot-window.vala
1 using Gtk;
2
3 class MainWindow : Window
4 {
5     private const int WINDOW_WIDTH = 400;
6     private const int WINDOW_HEIGHT = 500;
7
8     private UIManager ui_manager = new UIManager();
9     private Entry search_entry;
10     private VBox vbox_right;
11     private CustomVBox custom_vbox;
12     private VBox services_internal_vbox;
13
14     private Entry username_entry;
15     private Entry password_entry;
16
17     private ListStore listmodel;
18     private TreeModelFilter filter;
19
20     public IdentityManagerModel identities_manager;
21     private SList<IdCard>    candidates;
22
23 //    private MoonshotServer ipc_server;
24
25     private IdCard default_id_card;
26     public Queue<IdentityRequest> request_queue;
27
28     private HashTable<Gtk.Button, string> service_button_map;
29
30     private enum Columns
31     {
32         IDCARD_COL,
33         LOGO_COL,
34         ISSUER_COL,
35         USERNAME_COL,
36         PASSWORD_COL,
37         N_COLUMNS
38     }
39
40     private const string layout =
41 "<menubar name='MenuBar'>" +
42 "        <menu name='FileMenu' action='FileMenuAction'>" +
43 "            <menuitem name='AddIdCard' action='AddIdCardAction' />" +
44 "            <separator />" +
45 "            <menuitem name='Quit' action='QuitAction' />" +
46 "        </menu>" +
47 "" +
48 "        <menu name='HelpMenu' action='HelpMenuAction'>" +
49 "             <menuitem name='About' action='AboutAction' />" +
50 "        </menu>" +
51 "</menubar>";
52
53     public MainWindow()
54     {
55         request_queue = new Queue<IdentityRequest>();
56         
57         service_button_map = new HashTable<Gtk.Button, string> (direct_hash, direct_equal);
58
59         this.title = "Moonshoot";
60         this.set_position (WindowPosition.CENTER);
61         set_default_size (WINDOW_WIDTH, WINDOW_HEIGHT);
62
63         build_ui();
64         setup_identities_list();
65         load_id_cards();
66         connect_signals();
67   //      init_ipc_server();
68     }
69     
70     public void add_candidate (IdCard idcard)
71     {
72         candidates.append (idcard);
73     }
74
75     private bool visible_func (TreeModel model, TreeIter iter)
76     {
77         IdCard id_card;
78
79         model.get (iter,
80                    Columns.IDCARD_COL, out id_card);
81
82         if (id_card == null)
83             return false;
84         
85         if (candidates != null)
86         {
87             bool is_candidate = false;
88             foreach (IdCard candidate in candidates)
89             {
90                 if (candidate == id_card)
91                     is_candidate = true;
92             }
93             if (!is_candidate)
94                 return false;
95         }
96         
97         string entry_text = search_entry.get_text ();
98         if (entry_text == null || entry_text == "")
99         {
100             return true;
101         }
102
103         foreach (string search_text in entry_text.split(" "))
104         {
105             if (search_text == "")
106                 continue;
107          
108
109             string search_text_casefold = search_text.casefold ();
110
111             if (id_card.issuer != null)
112             {
113               string issuer_casefold = id_card.issuer;
114
115               if (issuer_casefold.contains (search_text_casefold))
116                   return true;
117             }
118
119             if (id_card.display_name != null)
120             {
121                 string display_name_casefold = id_card.display_name.casefold ();
122               
123                 if (display_name_casefold.contains (search_text_casefold))
124                     return true;
125             }
126             
127             if (id_card.services.length > 0)
128             {
129                 foreach (string service in id_card.services)
130                 {
131                     string service_casefold = service.casefold ();
132
133                     if (service_casefold.contains (search_text_casefold))
134                         return true;
135                 }
136             }
137         }
138         return false;
139     }
140
141     private void setup_identities_list ()
142     {
143        this.listmodel = new ListStore (Columns.N_COLUMNS, typeof (IdCard),
144                                                           typeof (Gdk.Pixbuf),
145                                                           typeof (string),
146                                                           typeof (string),
147                                                           typeof (string));
148       this.filter = new TreeModelFilter (listmodel, null);
149
150       filter.set_visible_func (visible_func);
151     }
152
153     private void search_entry_icon_press_cb (EntryIconPosition pos, Gdk.Event event)
154     {
155         if (pos == EntryIconPosition.PRIMARY)
156         {
157             print ("Search entry icon pressed\n");
158         }
159         else
160         {
161             this.search_entry.set_text ("");
162         }
163     }
164
165     private void search_entry_text_changed_cb ()
166     {
167         this.filter.refilter ();
168         redraw_id_card_widgets ();
169
170         var has_text = this.search_entry.get_text_length () > 0;
171         this.search_entry.set_icon_sensitive (EntryIconPosition.PRIMARY, has_text);
172         this.search_entry.set_icon_sensitive (EntryIconPosition.SECONDARY, has_text);
173
174         this.vbox_right.set_visible (false);
175     }
176
177     private bool search_entry_key_press_event_cb (Gdk.EventKey e)
178     {
179         if(Gdk.keyval_name(e.keyval) == "Escape")
180            this.search_entry.set_text("");
181
182         // Continue processing this event, since the
183         // text entry functionality needs to see it too.
184         return false;
185     }
186
187     private void load_id_cards ()
188     {
189  //       identities_manager = new IdentityManagerModel();
190         
191         if (identities_manager.id_card_list == null)
192           return;
193
194         foreach (IdCard id_card in identities_manager.id_card_list)
195         {
196             add_id_card_data (id_card);
197             add_id_card_widget (id_card);
198         }
199
200         this.default_id_card = identities_manager.id_card_list.data;
201     }
202
203     private void fill_details (IdCardWidget id_card_widget)
204     {
205        var id_card = id_card_widget.id_card;
206        this.username_entry.set_text (id_card.username);
207        this.password_entry.set_text (id_card.password ?? "");
208
209        var children = this.services_internal_vbox.get_children ();
210        foreach (var hbox in children)
211            hbox.destroy();
212        fill_services_vbox (id_card_widget.id_card);
213        identities_manager.store_id_cards();
214     }
215
216     private void show_details (IdCard id_card)
217     {
218        this.vbox_right.set_visible (!vbox_right.get_visible ());
219
220        if (this.vbox_right.get_visible () == false)
221        {
222            this.resize (WINDOW_WIDTH, WINDOW_HEIGHT);
223        }
224     }
225
226     private void details_identity_cb (IdCardWidget id_card_widget)
227     {
228        fill_details (id_card_widget);
229        show_details (id_card_widget.id_card);
230     }
231
232     private IdCard get_id_card_data (AddIdentityDialog dialog)
233     {
234         var id_card = new IdCard ();
235
236         id_card.display_name = dialog.display_name;
237         id_card.issuer = dialog.issuer;
238         if (id_card.issuer == "")
239             id_card.issuer = "Issuer";
240         id_card.username = dialog.username;
241         id_card.password = dialog.password;
242         id_card.services = {};
243         id_card.set_data("pixbuf", find_icon ("avatar-default", 48));
244
245         return id_card;
246     }
247
248     private void add_id_card_data (IdCard id_card)
249     {
250         TreeIter   iter;
251         Gdk.Pixbuf pixbuf;
252
253         this.listmodel.append (out iter);
254         pixbuf = id_card.get_data("pixbuf");
255         listmodel.set (iter,
256                        Columns.IDCARD_COL, id_card,
257                        Columns.LOGO_COL, pixbuf,
258                        Columns.ISSUER_COL, id_card.issuer,
259                        Columns.USERNAME_COL, id_card.username,
260                        Columns.PASSWORD_COL, id_card.password);
261     }
262
263     private void remove_id_card_data (IdCard id_card)
264     {
265         TreeIter iter;
266         string issuer;
267
268         if (listmodel.get_iter_first (out iter))
269         {
270             do
271             {
272                 listmodel.get (iter,
273                                Columns.ISSUER_COL, out issuer);
274
275                 if (id_card.issuer == issuer)
276                 {
277                     listmodel.remove (iter);
278                     break;
279                 }
280             }
281             while (listmodel.iter_next (ref iter));
282         }
283     }
284
285     private void add_id_card_widget (IdCard id_card)
286     {
287         var id_card_widget = new IdCardWidget (id_card);
288
289         this.custom_vbox.add_id_card_widget (id_card_widget);
290
291         id_card_widget.details_id.connect (details_identity_cb);
292         id_card_widget.remove_id.connect (remove_identity_cb);
293         id_card_widget.send_id.connect ((w) => send_identity_cb (w.id_card));
294         id_card_widget.expanded.connect (this.custom_vbox.receive_expanded_event);
295         id_card_widget.expanded.connect (fill_details);
296     }
297
298     /* This method finds a valid display name */
299     public bool display_name_is_valid (string name,
300                                        out string? candidate)
301     {
302         foreach (IdCard id_card in identities_manager.id_card_list)
303         {
304           if (id_card.display_name == name)
305           {
306             if (&candidate != null)
307             {
308               for (int i=0; i<1000; i++)
309               {
310                 string tmp = "%s %d".printf (name, i);
311                 if (display_name_is_valid (tmp, null))
312                 {
313                   candidate = tmp;
314                   break;
315                 }
316               }
317             }
318             return false;
319           }
320         }
321         
322         return true;
323     }
324     
325     public void insert_id_card (IdCard id_card)
326     {
327         string candidate;
328         
329         if (!display_name_is_valid (id_card.display_name, out candidate))
330         {
331           id_card.display_name = candidate;
332         }
333     
334         this.identities_manager.id_card_list.prepend (id_card);
335         this.identities_manager.store_id_cards ();
336
337         add_id_card_data (id_card);
338         add_id_card_widget (id_card);
339     }
340
341     public bool add_identity (IdCard id_card)
342     {
343         /* TODO: Check if display name already exists */
344
345         var dialog = new Gtk.MessageDialog (this,
346                                             Gtk.DialogFlags.DESTROY_WITH_PARENT,
347                                             Gtk.MessageType.QUESTION,
348                                             Gtk.ButtonsType.YES_NO,
349                                             _("Would you like to add '%s' ID Card to the ID Card Organizer?"),
350                                             id_card.display_name);
351
352         dialog.show_all ();
353         var ret = dialog.run ();
354         dialog.hide ();
355
356         if (ret == Gtk.ResponseType.YES) {
357             id_card.set_data ("pixbuf", find_icon ("avatar-default", 48));
358             this.insert_id_card (id_card);
359             return true;
360         }
361
362         return false;
363     }
364
365     private void add_identity_manual_cb ()
366     {
367         var dialog = new AddIdentityDialog ();
368         var result = dialog.run ();
369
370         switch (result) {
371         case ResponseType.OK:
372             insert_id_card (get_id_card_data (dialog));
373             break;
374         default:
375             break;
376         }
377         dialog.destroy ();
378     }
379
380     private void remove_id_card_widget (IdCardWidget id_card_widget)
381     {
382         remove_id_card_data (id_card_widget.id_card);
383
384         this.custom_vbox.remove_id_card_widget (id_card_widget);
385     }
386
387     private void remove_identity (IdCardWidget id_card_widget)
388     {
389         var id_card = id_card_widget.id_card;
390
391         this.identities_manager.id_card_list.remove (id_card);
392         this.identities_manager.store_id_cards ();
393
394         remove_id_card_widget (id_card_widget);
395     }
396
397     private void redraw_id_card_widgets ()
398     {
399         TreeIter iter;
400         IdCard id_card;
401
402         var children = this.custom_vbox.get_children ();
403         foreach (var id_card_widget in children)
404             id_card_widget.destroy();
405
406         if (filter.get_iter_first (out iter))
407         {
408             do
409             {
410                 filter.get (iter,
411                             Columns.IDCARD_COL, out id_card);
412
413                 add_id_card_widget (id_card);
414             }
415             while (filter.iter_next (ref iter));
416         }
417     }
418
419     private void remove_identity_cb (IdCardWidget id_card_widget)
420     {
421         var id_card = id_card_widget.id_card;
422
423         var dialog = new MessageDialog (null,
424                                         DialogFlags.DESTROY_WITH_PARENT,
425                                         MessageType.INFO,
426                                         Gtk.ButtonsType.YES_NO,
427                                         _("Are you sure you want to delete %s ID Card?"), id_card.issuer);
428         var result = dialog.run ();
429         switch (result) {
430         case ResponseType.YES:
431             remove_identity (id_card_widget);
432             break;
433         default:
434             break;
435         }
436         dialog.destroy ();
437     }
438
439     public void select_identity (IdentityRequest request)
440     {
441         IdCard identity = null;
442
443         this.request_queue.push_tail (request);
444         
445         if (custom_vbox.current_idcard != null &&
446             custom_vbox.current_idcard.send_button != null)
447           custom_vbox.current_idcard.send_button.set_sensitive (true);
448
449         if (request.select_default)
450         {
451             identity = default_id_card;
452         }
453
454         if (identity == null)
455         {
456             bool has_nai = request.nai != null && request.nai != "";
457             bool has_srv = request.service != null && request.service != "";
458             bool confirm = false;
459             IdCard nai_provided = null;
460
461             foreach (IdCard id in identities_manager.id_card_list)
462             {
463                 /* If NAI matches we add id card to the candidate list */
464                 if (has_nai && request.nai == id.nai)
465                 {
466                     nai_provided = id;
467                     add_candidate (id);
468                     continue;
469                 }
470
471                 /* If any service matches we add id card to the candidate list */
472                 if (has_srv)
473                 {
474                     foreach (string srv in id.services)
475                     {
476                         if (request.service == srv)
477                         {
478                             add_candidate (id);
479                             continue;
480                         }
481                     }
482                 }
483             }
484
485             /* If more than one candidate we dissasociate service from all ids */
486             if (has_srv && candidates.length() > 1)
487             {
488                 foreach (IdCard id in candidates)
489                 {
490                     int i = 0;
491                     SList<string> services_list = null;
492                     bool has_service = false;
493
494                     foreach (string srv in id.services)
495                     {
496                         if (srv == request.service)
497                         {
498                             has_service = true;
499                             continue;
500                         }
501                         services_list.append (srv);
502                     }
503                     
504                     if (!has_service)
505                         continue;
506
507                     if (services_list.length () == 0)
508                     {
509                         id.services = {};
510                         continue;
511                     }
512
513                     string[] services = new string[services_list.length ()];
514                     foreach (string srv in services_list)
515                     {
516                         services[i] = srv;
517                         i++;
518                     }
519
520                     id.services = services;
521                 }
522             }
523
524             identities_manager.store_id_cards ();
525
526             /* If there are no candidates we use the service matching rules */
527             if (candidates.length () == 0)
528             {
529                 foreach (IdCard id in identities_manager.id_card_list)
530                 {
531                     foreach (Rule rule in id.rules)
532                     {
533                         if (!match_service_pattern (request.service, rule.pattern))
534                             continue;
535
536                         candidates.append (id);
537
538                         if (rule.always_confirm == "true")
539                             confirm = true;
540                     }
541                 }
542             }
543             
544             if (candidates.length () > 1)
545             {
546                 if (has_nai && nai_provided != null)
547                 {
548                     identity = nai_provided;
549                     confirm = false;
550                 }
551                 else
552                     confirm = true;
553             }
554             else
555                 identity = candidates.nth_data (0);
556
557             /* TODO: If candidate list empty return fail */
558             
559             if (confirm)
560             {
561                 filter.refilter();
562                 redraw_id_card_widgets ();
563                 show ();
564                 return;
565             }
566         }
567         // Send back the identity (we can't directly run the
568         // callback because we may be being called from a 'yield')
569         Idle.add (() => { send_identity_cb (identity); return false; });
570         return;
571     }
572     
573     private bool match_service_pattern (string service, string pattern)
574     {
575         var pspec = new PatternSpec (pattern);
576         return pspec.match_string (service);
577     }
578
579     public void send_identity_cb (IdCard identity)
580     {
581         return_if_fail (request_queue.length > 0);
582
583         var request = this.request_queue.pop_head ();
584         bool reset_password = false;
585
586         if (request.service != null && request.service != "")
587         {
588             string[] services = new string[identity.services.length + 1];
589
590             for (int i = 0; i < identity.services.length; i++)
591                 services[i] = identity.services[i];
592
593             services[identity.services.length] = request.service;
594
595             identity.services = services;
596
597             identities_manager.store_id_cards();
598         }
599
600         if (identity.password == null)
601         {
602             var dialog = new AddPasswordDialog ();
603             var result = dialog.run ();
604
605             switch (result) {
606             case ResponseType.OK:
607                 identity.password = dialog.password;
608                 reset_password = ! dialog.remember;
609                 break;
610             default:
611                 identity = null;
612                 break;
613             }
614
615             dialog.destroy ();
616         }
617
618         if (this.request_queue.is_empty())
619             this.hide ();
620
621         if (identity != null)
622             this.default_id_card = identity;
623
624         request.return_identity (identity);
625
626         if (reset_password)
627             identity.password = null;
628
629         candidates = null;
630     }
631
632     private void label_make_bold (Label label)
633     {
634         var font_desc = new Pango.FontDescription ();
635
636         font_desc.set_weight (Pango.Weight.BOLD);
637
638         /* This will only affect the weight of the font, the rest is
639          * from the current state of the widget, which comes from the
640          * theme or user prefs, since the font desc only has the
641          * weight flag turned on.
642          */
643         label.modify_font (font_desc);
644     }
645
646     private void fill_services_vbox (IdCard id_card)
647     {
648         int i = 0;
649         var n_columns = id_card.services.length;
650
651         var services_table = new Table (n_columns, 2, false);
652         services_table.set_col_spacings (10);
653         services_table.set_row_spacings (10);
654         this.services_internal_vbox.add (services_table);
655         
656         service_button_map.remove_all ();
657
658         foreach (string service in id_card.services)
659         {
660             var label = new Label (service);
661             label.set_alignment (0, (float) 0.5);
662 #if VALA_0_12
663             var remove_button = new Button.from_stock (Stock.REMOVE);
664 #else
665             var remove_button = new Button.from_stock (STOCK_REMOVE);
666 #endif
667
668
669             service_button_map.insert (remove_button, service);
670             
671             remove_button.clicked.connect ((remove_button) =>
672             {
673               var dialog = new Gtk.MessageDialog (this,
674                                       Gtk.DialogFlags.DESTROY_WITH_PARENT,
675                                       Gtk.MessageType.QUESTION,
676                                       Gtk.ButtonsType.YES_NO,
677                                       _("Are you sure you want to stop '%s' ID Card to use %s?"),
678                                       custom_vbox.current_idcard.id_card.display_name);
679               var ret = dialog.run();
680               dialog.hide();
681               
682               if (ret == Gtk.ResponseType.YES)
683               {
684                 IdCard idcard = custom_vbox.current_idcard.id_card;
685                 var candidate = service_button_map.lookup (remove_button);
686
687                 SList<string> services = new SList<string>();
688                 
689                 foreach (string srv in idcard.services)
690                 {
691                   if (srv == candidate)
692                     continue;
693                   services.append (srv);
694                 }
695                 
696                 idcard.services = new string[services.length()];
697                 for (int j=0; j<idcard.services.length; j++)
698                 {
699                   idcard.services[j] = services.nth_data(j);
700                 }
701                 
702                 var children = services_internal_vbox.get_children ();
703                 foreach (var hbox in children)
704                   hbox.destroy();
705                 
706                 fill_services_vbox (idcard);
707                 custom_vbox.current_idcard.update_id_card_label ();
708               }
709               
710             });
711             services_table.attach_defaults (label, 0, 1, i, i+1);
712             services_table.attach_defaults (remove_button, 1, 2, i, i+1);
713             i++;
714         }
715         this.services_internal_vbox.show_all ();
716     }
717
718     private void on_about_action ()
719     {
720         string[] authors = {
721             "Javier Jardón <jjardon@codethink.co.uk>",
722             "Sam Thursfield <samthursfield@codethink.co.uk>",
723             "Alberto Ruiz <alberto.ruiz@codethink.co.uk>",
724             null
725         };
726
727         string copyright = "Copyright 2011 JANET";
728
729         string license =
730 """
731 Copyright (c) 2011, JANET(UK)
732 All rights reserved.
733
734 Redistribution and use in source and binary forms, with or without
735 modification, are permitted provided that the following conditions
736 are met:
737
738 1. Redistributions of source code must retain the above copyright
739    notice, this list of conditions and the following disclaimer.
740
741 2. Redistributions in binary form must reproduce the above copyright
742    notice, this list of conditions and the following disclaimer in the
743    documentation and/or other materials provided with the distribution.
744
745 3. Neither the name of JANET(UK) nor the names of its contributors
746    may be used to endorse or promote products derived from this software
747    without specific prior written permission.
748
749 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"
750 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
751 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
752 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
753 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
754 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
755 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
756 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
757 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
758 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
759 SUCH DAMAGE.
760 """;
761
762         Gtk.show_about_dialog (this,
763             "comments", _("Moonshot project UI"),
764             "copyright", copyright,
765             "website", "http://www.project-moonshot.org/",
766             "license", license,
767             "website-label", _("Visit the Moonshot project web site"),
768             "authors", authors,
769             "translator-credits", _("translator-credits"),
770             null
771         );
772     }
773
774     private Gtk.ActionEntry[] create_actions() {
775         Gtk.ActionEntry[] actions = new Gtk.ActionEntry[0];
776
777         Gtk.ActionEntry filemenu = { "FileMenuAction",
778                                      null,
779                                      N_("_File"),
780                                      null, null, null };
781         actions += filemenu;
782         Gtk.ActionEntry add = { "AddIdCardAction",
783 #if VALA_0_12
784                                 Stock.ADD,
785 #else
786                                 STOCK_ADD,
787 #endif
788                                 N_("Add ID Card"),
789                                 null,
790                                 N_("Add a new ID Card"),
791                                 add_identity_manual_cb };
792         actions += add;
793         Gtk.ActionEntry quit = { "QuitAction",
794 #if VALA_0_12
795                                  Stock.QUIT,
796 #else
797                                  STOCK_QUIT,
798 #endif
799                                  N_("Quit"),
800                                  "<control>Q",
801                                  N_("Quit the application"),
802                                  Gtk.main_quit };
803         actions += quit;
804
805         Gtk.ActionEntry helpmenu = { "HelpMenuAction",
806                                      null,
807                                      N_("_Help"),
808                                      null, null, null };
809         actions += helpmenu;
810         Gtk.ActionEntry about = { "AboutAction",
811 #if VALA_0_12
812                                   Stock.ABOUT,
813 #else
814                                   STOCK_ABOUT,
815 #endif
816                                   N_("About"),
817                                   null,
818                                   N_("About this application"),
819                                   on_about_action };
820         actions += about;
821
822         return actions;
823     }
824
825
826     private void create_ui_manager ()
827     {
828         Gtk.ActionGroup action_group = new Gtk.ActionGroup ("GeneralActionGroup");
829         action_group.add_actions (create_actions (), this);
830         ui_manager.insert_action_group (action_group, 0);
831         try
832         {
833             ui_manager.add_ui_from_string (layout, -1);
834         }
835         catch (Error e)
836         {
837             stderr.printf ("%s\n", e.message);
838         }
839         ui_manager.ensure_update ();
840     }
841
842     private void build_ui()
843     {
844         create_ui_manager ();
845
846         this.search_entry = new Entry();
847
848         set_atk_name_description (search_entry, _("Search entry"), _("Search for a specific ID Card"));
849         this.search_entry.set_icon_from_pixbuf (EntryIconPosition.PRIMARY,
850                                                 find_icon_sized ("edit-find-symbolic", Gtk.IconSize.MENU));
851         this.search_entry.set_icon_tooltip_text (EntryIconPosition.PRIMARY,
852                                                  _("Search identity or service"));
853         this.search_entry.set_icon_sensitive (EntryIconPosition.PRIMARY, false);
854
855         this.search_entry.set_icon_from_pixbuf (EntryIconPosition.SECONDARY,
856                                                 find_icon_sized ("edit-clear-symbolic", Gtk.IconSize.MENU));
857         this.search_entry.set_icon_tooltip_text (EntryIconPosition.SECONDARY,
858                                                  _("Clear the current search"));
859         this.search_entry.set_icon_sensitive (EntryIconPosition.SECONDARY, false);
860
861
862         this.search_entry.icon_press.connect (search_entry_icon_press_cb);
863         this.search_entry.notify["text"].connect (search_entry_text_changed_cb);
864         this.search_entry.key_press_event.connect(search_entry_key_press_event_cb);
865
866         this.custom_vbox = new CustomVBox (this, false, 6);
867
868         var viewport = new Viewport (null, null);
869         viewport.set_border_width (6);
870         viewport.set_shadow_type (ShadowType.NONE);
871         viewport.add (custom_vbox);
872         var scroll = new ScrolledWindow (null, null);
873         scroll.set_policy (PolicyType.NEVER, PolicyType.AUTOMATIC);
874         scroll.set_shadow_type (ShadowType.IN);
875         scroll.add_with_viewport (viewport);
876
877         var vbox_left = new VBox (false, 0);
878         vbox_left.pack_start (search_entry, false, false, 6);
879         vbox_left.pack_start (scroll, true, true, 0);
880         vbox_left.set_size_request (WINDOW_WIDTH, 0);
881
882         var login_vbox_title = new Label (_("Login: "));
883         label_make_bold (login_vbox_title);
884         login_vbox_title.set_alignment (0, (float) 0.5);
885         var username_label = new Label (_("Username:"));
886         username_label.set_alignment (1, (float) 0.5);
887         this.username_entry = new Entry ();
888         var password_label = new Label (_("Password:"));
889         password_label.set_alignment (1, (float) 0.5);
890         this.password_entry = new Entry ();
891         password_entry.set_invisible_char ('*');
892         password_entry.set_visibility (false);
893         var remember_checkbutton = new CheckButton.with_label (_("Remember password"));
894         var login_table = new Table (3, 3, false);
895         login_table.set_col_spacings (10);
896         login_table.set_row_spacings (10);
897         login_table.attach_defaults (username_label, 0, 1, 0, 1);
898         login_table.attach_defaults (username_entry, 1, 2, 0, 1);
899         login_table.attach_defaults (password_label, 0, 1, 1, 2);
900         login_table.attach_defaults (password_entry, 1, 2, 1, 2);
901         login_table.attach_defaults (remember_checkbutton,  1, 2, 2, 3);
902         var login_vbox_alignment = new Alignment (0, 0, 0, 0);
903         login_vbox_alignment.set_padding (0, 0, 12, 0);
904         login_vbox_alignment.add (login_table);
905         var login_vbox = new VBox (false, 6);
906         login_vbox.pack_start (login_vbox_title, false, true, 0);
907         login_vbox.pack_start (login_vbox_alignment, false, true, 0);
908
909         var services_vbox_title = new Label (_("Services:"));
910         label_make_bold (services_vbox_title);
911         services_vbox_title.set_alignment (0, (float) 0.5);
912         var services_vbox_alignment = new Alignment (0, 0, 0, 0);
913         services_vbox_alignment.set_padding (0, 0, 12, 0);
914         this.services_internal_vbox = new VBox (true, 6);
915         services_vbox_alignment.add (services_internal_vbox);
916         var services_vbox = new VBox (false, 6);
917         services_vbox.pack_start (services_vbox_title, false, true, 0);
918         services_vbox.pack_start (services_vbox_alignment, false, true, 0);
919
920         this.vbox_right = new VBox (false, 18);
921         vbox_right.pack_start (login_vbox, false, true, 0);
922         vbox_right.pack_start (services_vbox, false, true, 0);
923
924         var hbox = new HBox (false, 12);
925         hbox.pack_start (vbox_left, true, true, 0);
926         hbox.pack_start (vbox_right, false, false, 0);
927
928         var main_vbox = new VBox (false, 0);
929         main_vbox.set_border_width (12);
930         var menubar = this.ui_manager.get_widget ("/MenuBar");
931         main_vbox.pack_start (menubar, false, false, 0);
932         main_vbox.pack_start (hbox, true, true, 0);
933         add (main_vbox);
934
935         main_vbox.show_all();
936         this.vbox_right.hide ();
937     }
938
939     private void set_atk_name_description (Widget widget, string name, string description)
940     {
941        var atk_widget = widget.get_accessible ();
942
943        atk_widget.set_name (name);
944        atk_widget.set_description (description);
945     }
946
947     private void connect_signals()
948     {
949         this.destroy.connect (Gtk.main_quit);
950     }
951 /*
952 #if IPC_MSRPC
953     private void init_ipc_server ()
954     {
955         // Errors will currently be sent via g_log - ie. to an
956         // obtrusive message box, on Windows
957         //
958         this.ipc_server = MoonshotServer.get_instance ();
959         MoonshotServer.start (this);
960     }
961 #elif IPC_DBUS_GLIB
962     private void init_ipc_server ()
963     {
964         try {
965             var conn = DBus.Bus.get (DBus.BusType.SESSION);
966             dynamic DBus.Object bus = conn.get_object ("org.freedesktop.DBus",
967                                                        "/org/freedesktop/DBus",
968                                                        "org.freedesktop.DBus");
969
970             // try to register service in session bus
971             uint reply = bus.request_name ("org.janet.Moonshot", (uint) 0);
972             assert (reply == DBus.RequestNameReply.PRIMARY_OWNER);
973
974             this.ipc_server = new MoonshotServer (this);
975             conn.register_object ("/org/janet/moonshot", ipc_server);
976         }
977         catch (DBus.Error e)
978         {
979             stderr.printf ("%s\n", e.message);
980         }
981     }
982 #else
983     private void bus_acquired_cb (DBusConnection conn)
984     {
985         try {
986             conn.register_object ("/org/janet/moonshot", ipc_server);
987         }
988         catch (Error e)
989         {
990             stderr.printf ("%s\n", e.message);
991         }
992     }
993
994     private void init_ipc_server ()
995     {
996         this.ipc_server = new MoonshotServer (this);
997         GLib.Bus.own_name (GLib.BusType.SESSION,
998                            "org.janet.Moonshot",
999                            GLib.BusNameOwnerFlags.NONE,
1000                            bus_acquired_cb,
1001                            (conn, name) => {},
1002                            (conn, name) => {
1003                                error ("Couldn't own name %s on DBus.", name);
1004                            });
1005     }
1006 #endif
1007 */
1008 }