3 class MainWindow : Window
5 private const int WINDOW_WIDTH = 400;
6 private const int WINDOW_HEIGHT = 500;
8 private UIManager ui_manager = new UIManager();
9 private Entry search_entry;
10 private VBox vbox_rigth;
11 private CustomVBox custom_vbox;
12 private VBox services_internal_vbox;
14 private Entry username_entry;
15 private Entry password_entry;
17 private ListStore listmodel;
18 private TreeModelFilter filter;
20 private IdentitiesManager identities_manager;
22 private MoonshotServer ipc_server;
24 public IdCardWidget selected_id_card_widget;
26 private SourceFunc callback;
38 private const string layout =
40 <menubar name='MenuBar'>
41 <menu name='FileMenu' action='FileMenuAction'>
42 <menuitem name='AddIdCard' action='AddIdCardAction' />
44 <menuitem name='Quit' action='QuitAction' />
47 <menu name='HelpMenu' action='HelpMenuAction'>
48 <menuitem name='About' action='AboutAction' />
55 this.title = "Moonshoot";
56 this.set_position (WindowPosition.CENTER);
57 set_default_size (WINDOW_WIDTH, WINDOW_HEIGHT);
60 setup_identities_list();
61 load_gss_eap_id_file();
67 private bool visible_func (TreeModel model, TreeIter iter)
71 string issuer_casefold;
72 string search_text_casefold;
75 Columns.ISSUER_COL, out issuer);
76 search_text = this.search_entry.get_text ();
78 if (issuer == null || search_text == null)
81 issuer_casefold = issuer.casefold ();
82 search_text_casefold = search_text.casefold ();
84 if (issuer_casefold.contains (search_text_casefold))
90 private void setup_identities_list ()
92 this.listmodel = new ListStore (Columns.N_COLUMNS, typeof (IdCard),
97 this.filter = new TreeModelFilter (listmodel, null);
99 filter.set_visible_func (visible_func);
102 private void search_entry_icon_press_cb (EntryIconPosition pos, Gdk.Event event)
104 if (pos == EntryIconPosition.PRIMARY)
106 print ("Search entry icon pressed\n");
110 this.search_entry.set_text ("");
114 private void search_entry_text_changed_cb ()
116 this.filter.refilter ();
117 redraw_id_card_widgets ();
119 var has_text = this.search_entry.get_text_length () > 0;
120 this.search_entry.set_icon_sensitive (EntryIconPosition.PRIMARY, has_text);
121 this.search_entry.set_icon_sensitive (EntryIconPosition.SECONDARY, has_text);
123 this.vbox_rigth.set_visible (false);
124 this.resize (WINDOW_WIDTH, WINDOW_HEIGHT);
127 private bool search_entry_key_press_event_cb (Gdk.EventKey e)
129 if(Gdk.keyval_name(e.keyval) == "Escape")
130 this.search_entry.set_text("");
132 // Continue processing this event, since the
133 // text entry functionality needs to see it too.
137 private void load_gss_eap_id_file ()
141 this.identities_manager = new IdentitiesManager ();
143 id_card = this.identities_manager.load_gss_eap_id_file ();
146 add_id_card_data (id_card);
147 add_id_card_widget (id_card);
151 private void load_id_cards ()
153 this.identities_manager = new IdentitiesManager ();
155 foreach (IdCard id_card in identities_manager.id_card_list)
157 add_id_card_data (id_card);
158 add_id_card_widget (id_card);
162 private void fill_details (IdCardWidget id_card_widget)
164 var id_card = id_card_widget.id_card;
165 this.username_entry.set_text (id_card.username);
166 this.password_entry.set_text (id_card.password);
168 var children = this.services_internal_vbox.get_children ();
169 foreach (var hbox in children)
171 fill_services_vbox (id_card_widget.id_card);
174 private void show_details (IdCard id_card)
176 this.vbox_rigth.set_visible (!vbox_rigth.get_visible ());
178 if (this.vbox_rigth.get_visible () == false)
180 this.resize (WINDOW_WIDTH, WINDOW_HEIGHT);
184 private void details_identity_cb (IdCardWidget id_card_widget)
186 fill_details (id_card_widget);
187 show_details (id_card_widget.id_card);
190 private IdCard get_id_card_data (AddIdentityDialog dialog)
192 var id_card = new IdCard ();
194 id_card.issuer = dialog.issuer;
195 if (id_card.issuer == "")
196 id_card.issuer = "Issuer";
197 id_card.username = dialog.username;
198 id_card.password = dialog.password;
199 id_card.nai = id_card.username + "@" + id_card.issuer;
200 id_card.pixbuf = find_icon ("avatar-default", 48);
201 id_card.services = {"email","jabber","irc"};
206 private void add_id_card_data (IdCard id_card)
210 this.listmodel.append (out iter);
212 Columns.IDCARD_COL, id_card,
213 Columns.LOGO_COL, id_card.pixbuf,
214 Columns.ISSUER_COL, id_card.issuer,
215 Columns.USERNAME_COL, id_card.username,
216 Columns.PASSWORD_COL, id_card.password);
219 private void remove_id_card_data (IdCard id_card)
224 if (listmodel.get_iter_first (out iter))
229 Columns.ISSUER_COL, out issuer);
231 if (id_card.issuer == issuer)
233 listmodel.remove (iter);
237 while (listmodel.iter_next (ref iter));
241 private void add_id_card_widget (IdCard id_card)
243 var id_card_widget = new IdCardWidget (id_card);
245 this.custom_vbox.add_id_card_widget (id_card_widget);
247 id_card_widget.details_id.connect (details_identity_cb);
248 id_card_widget.remove_id.connect (remove_identity_cb);
249 id_card_widget.send_id.connect (send_identity_cb);
250 id_card_widget.expanded.connect (this.custom_vbox.receive_expanded_event);
251 id_card_widget.expanded.connect (fill_details);
254 private void add_identity (AddIdentityDialog dialog)
256 var id_card = get_id_card_data (dialog);
258 this.identities_manager.id_card_list.prepend (id_card);
259 this.identities_manager.store_id_cards ();
260 this.identities_manager.store_gss_eap_id_file (id_card);
262 add_id_card_data (id_card);
263 add_id_card_widget (id_card);
266 private void add_identity_cb ()
268 var dialog = new AddIdentityDialog ();
269 var result = dialog.run ();
272 case ResponseType.OK:
273 add_identity (dialog);
281 private void remove_id_card_widget (IdCardWidget id_card_widget)
283 remove_id_card_data (id_card_widget.id_card);
285 this.custom_vbox.remove_id_card_widget (id_card_widget);
288 private void remove_identity (IdCardWidget id_card_widget)
290 var id_card = id_card_widget.id_card;
292 this.identities_manager.id_card_list.remove (id_card);
293 this.identities_manager.store_id_cards ();
294 this.identities_manager.store_gss_eap_id_file (null);
296 remove_id_card_widget (id_card_widget);
299 private void redraw_id_card_widgets ()
304 var children = this.custom_vbox.get_children ();
305 foreach (var id_card_widget in children)
306 id_card_widget.destroy();
308 if (filter.get_iter_first (out iter))
313 Columns.IDCARD_COL, out id_card);
315 add_id_card_widget (id_card);
317 while (filter.iter_next (ref iter));
321 private void remove_identity_cb (IdCardWidget id_card_widget)
323 var id_card = id_card_widget.id_card;
325 var dialog = new MessageDialog (null,
326 DialogFlags.DESTROY_WITH_PARENT,
328 Gtk.ButtonsType.YES_NO,
329 _("Are you sure you want to delete %s ID Card?"), id_card.issuer);
330 var result = dialog.run ();
332 case ResponseType.YES:
333 remove_identity (id_card_widget);
341 public void set_callback (owned SourceFunc callback)
344 this.callback = (owned) callback;
346 this.callback = () => callback ();
350 public void send_identity_cb (IdCardWidget id_card_widget)
352 this.selected_id_card_widget = id_card_widget;
354 if (id_card_widget.id_card.password == null)
356 var dialog = new AddPasswordDialog ();
357 var result = dialog.run ();
360 case ResponseType.OK:
361 selected_id_card_widget.id_card.password = dialog.password;
378 private void label_make_bold (Label label)
380 var font_desc = new Pango.FontDescription ();
382 font_desc.set_weight (Pango.Weight.BOLD);
384 /* This will only affect the weight of the font, the rest is
385 * from the current state of the widget, which comes from the
386 * theme or user prefs, since the font desc only has the
387 * weight flag turned on.
389 label.modify_font (font_desc);
392 private void fill_services_vbox (IdCard id_card)
395 var n_columns = id_card.services.length;
397 var services_table = new Table (n_columns, 2, false);
398 services_table.set_col_spacings (10);
399 services_table.set_row_spacings (10);
400 this.services_internal_vbox.add (services_table);
402 foreach (string service in id_card.services)
404 var label = new Label (service);
405 label.set_alignment (0, (float) 0.5);
407 var remove_button = new Button.from_stock (Stock.REMOVE);
409 var remove_button = new Button.from_stock (STOCK_REMOVE);
411 services_table.attach_defaults (label, 0, 1, i, i+1);
412 services_table.attach_defaults (remove_button, 1, 2, i, i+1);
415 this.services_internal_vbox.show_all ();
418 private void on_about_action ()
421 "Javier Jardón <jjardon@codethink.co.uk>",
422 "Sam Thursfield <samthursfield@codethink.co.uk>",
426 string copyright = "Copyright 2011 JANET";
430 Copyright (c) 2011, JANET(UK)
433 Redistribution and use in source and binary forms, with or without
434 modification, are permitted provided that the following conditions
437 1. Redistributions of source code must retain the above copyright
438 notice, this list of conditions and the following disclaimer.
440 2. Redistributions in binary form must reproduce the above copyright
441 notice, this list of conditions and the following disclaimer in the
442 documentation and/or other materials provided with the distribution.
444 3. Neither the name of JANET(UK) nor the names of its contributors
445 may be used to endorse or promote products derived from this software
446 without specific prior written permission.
448 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"
449 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
450 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
451 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
452 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
453 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
454 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
455 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
456 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
457 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
461 Gtk.show_about_dialog (this,
462 "comments", _("Moonshot project UI"),
463 "copyright", copyright,
464 "website", "http://www.project-moonshot.org/",
466 "website-label", _("Visit the Moonshot project web site"),
468 "translator-credits", _("translator-credits"),
473 private Gtk.ActionEntry[] create_actions() {
474 Gtk.ActionEntry[] actions = new Gtk.ActionEntry[0];
476 Gtk.ActionEntry filemenu = { "FileMenuAction",
481 Gtk.ActionEntry add = { "AddIdCardAction",
489 N_("Add a new ID Card"),
492 Gtk.ActionEntry quit = { "QuitAction",
500 N_("Quit the application"),
504 Gtk.ActionEntry helpmenu = { "HelpMenuAction",
509 Gtk.ActionEntry about = { "AboutAction",
517 N_("About this application"),
525 private void create_ui_manager ()
527 Gtk.ActionGroup action_group = new Gtk.ActionGroup ("GeneralActionGroup");
528 action_group.add_actions (create_actions (), this);
529 ui_manager.insert_action_group (action_group, 0);
532 ui_manager.add_ui_from_string (layout, -1);
536 stderr.printf ("%s\n", e.message);
538 ui_manager.ensure_update ();
541 private void build_ui()
543 create_ui_manager ();
545 this.search_entry = new Entry();
547 set_atk_name_description (search_entry, _("Search entry"), _("Search for a specific ID Card"));
548 this.search_entry.set_icon_from_pixbuf (EntryIconPosition.PRIMARY,
549 find_icon_sized ("edit-find-symbolic", Gtk.IconSize.MENU));
550 this.search_entry.set_icon_tooltip_text (EntryIconPosition.PRIMARY,
551 _("Search identity or service"));
552 this.search_entry.set_icon_sensitive (EntryIconPosition.PRIMARY, false);
554 this.search_entry.set_icon_from_pixbuf (EntryIconPosition.SECONDARY,
555 find_icon_sized ("edit-clear-symbolic", Gtk.IconSize.MENU));
556 this.search_entry.set_icon_tooltip_text (EntryIconPosition.SECONDARY,
557 _("Clear the current search"));
558 this.search_entry.set_icon_sensitive (EntryIconPosition.SECONDARY, false);
561 this.search_entry.icon_press.connect (search_entry_icon_press_cb);
562 this.search_entry.notify["text"].connect (search_entry_text_changed_cb);
563 this.search_entry.key_press_event.connect(search_entry_key_press_event_cb);
565 this.custom_vbox = new CustomVBox (false, 6);
567 var viewport = new Viewport (null, null);
568 viewport.set_border_width (6);
569 viewport.set_shadow_type (ShadowType.NONE);
570 viewport.add (custom_vbox);
571 var scroll = new ScrolledWindow (null, null);
572 scroll.set_policy (PolicyType.NEVER, PolicyType.AUTOMATIC);
573 scroll.set_shadow_type (ShadowType.IN);
574 scroll.add_with_viewport (viewport);
576 var vbox_left = new VBox (false, 0);
577 vbox_left.pack_start (search_entry, false, false, 6);
578 vbox_left.pack_start (scroll, true, true, 0);
579 vbox_left.set_size_request (WINDOW_WIDTH, 0);
581 var login_vbox_title = new Label (_("Login: "));
582 label_make_bold (login_vbox_title);
583 login_vbox_title.set_alignment (0, (float) 0.5);
584 var username_label = new Label (_("Username:"));
585 username_label.set_alignment (1, (float) 0.5);
586 this.username_entry = new Entry ();
587 var password_label = new Label (_("Password:"));
588 password_label.set_alignment (1, (float) 0.5);
589 this.password_entry = new Entry ();
590 password_entry.set_invisible_char ('*');
591 password_entry.set_visibility (false);
592 var remember_checkbutton = new CheckButton.with_label (_("Remember password"));
593 var login_table = new Table (3, 3, false);
594 login_table.set_col_spacings (10);
595 login_table.set_row_spacings (10);
596 login_table.attach_defaults (username_label, 0, 1, 0, 1);
597 login_table.attach_defaults (username_entry, 1, 2, 0, 1);
598 login_table.attach_defaults (password_label, 0, 1, 1, 2);
599 login_table.attach_defaults (password_entry, 1, 2, 1, 2);
600 login_table.attach_defaults (remember_checkbutton, 1, 2, 2, 3);
601 var login_vbox_alignment = new Alignment (0, 0, 0, 0);
602 login_vbox_alignment.set_padding (0, 0, 12, 0);
603 login_vbox_alignment.add (login_table);
604 var login_vbox = new VBox (false, 6);
605 login_vbox.pack_start (login_vbox_title, false, true, 0);
606 login_vbox.pack_start (login_vbox_alignment, false, true, 0);
608 var services_vbox_title = new Label (_("Services:"));
609 label_make_bold (services_vbox_title);
610 services_vbox_title.set_alignment (0, (float) 0.5);
611 var services_vbox_alignment = new Alignment (0, 0, 0, 0);
612 services_vbox_alignment.set_padding (0, 0, 12, 0);
613 this.services_internal_vbox = new VBox (true, 6);
614 services_vbox_alignment.add (services_internal_vbox);
615 var services_vbox = new VBox (false, 6);
616 services_vbox.pack_start (services_vbox_title, false, true, 0);
617 services_vbox.pack_start (services_vbox_alignment, false, true, 0);
619 this.vbox_rigth = new VBox (false, 18);
620 vbox_rigth.pack_start (login_vbox, false, true, 0);
621 vbox_rigth.pack_start (services_vbox, false, true, 0);
623 var hbox = new HBox (false, 12);
624 hbox.pack_start (vbox_left, false, false, 0);
625 hbox.pack_start (vbox_rigth, false, false, 0);
627 var main_vbox = new VBox (false, 0);
628 main_vbox.set_border_width (12);
629 var menubar = this.ui_manager.get_widget ("/MenuBar");
630 main_vbox.pack_start (menubar, false, false, 0);
631 main_vbox.pack_start (hbox, true, true, 0);
634 main_vbox.show_all();
635 this.vbox_rigth.hide ();
638 private void set_atk_name_description (Widget widget, string name, string description)
640 var atk_widget = widget.get_accessible ();
642 atk_widget.set_name (name);
643 atk_widget.set_description (description);
646 private void connect_signals()
648 this.destroy.connect (Gtk.main_quit);
651 private void init_ipc_server ()
654 /* Errors will currently be sent via g_log - ie. to an
655 * obtrusive message box, on Windows
657 this.ipc_server = MoonshotServer.get_instance ();
658 MoonshotServer.start (this);
661 var conn = DBus.Bus.get (DBus.BusType.SESSION);
662 dynamic DBus.Object bus = conn.get_object ("org.freedesktop.DBus",
663 "/org/freedesktop/DBus",
664 "org.freedesktop.DBus");
666 // try to register service in session bus
667 uint reply = bus.request_name ("org.janet.Moonshot", (uint) 0);
668 assert (reply == DBus.RequestNameReply.PRIMARY_OWNER);
670 this.ipc_server = new MoonshotServer (this);
671 conn.register_object ("/org/janet/moonshot", ipc_server);
676 stderr.printf ("%s\n", e.message);
681 public static int main(string[] args)
686 // Force specific theme settings on Windows without requiring a gtkrc file
687 Gtk.Settings settings = Gtk.Settings.get_default ();
688 settings.set_string_property ("gtk-theme-name", "ms-windows", "moonshot");
689 settings.set_long_property ("gtk-menu-images", 0, "moonshot");
692 Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
693 Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8");
694 Intl.textdomain (Config.GETTEXT_PACKAGE);
696 var window = new MainWindow();