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)
343 this.callback = (owned) callback;
346 public void send_identity_cb (IdCardWidget id_card_widget)
348 this.selected_id_card_widget = id_card_widget;
350 if (id_card_widget.id_card.password == null)
352 var dialog = new AddPasswordDialog ();
353 var result = dialog.run ();
356 case ResponseType.OK:
373 private void label_make_bold (Label label)
375 var font_desc = new Pango.FontDescription ();
377 font_desc.set_weight (Pango.Weight.BOLD);
379 /* This will only affect the weight of the font, the rest is
380 * from the current state of the widget, which comes from the
381 * theme or user prefs, since the font desc only has the
382 * weight flag turned on.
384 label.modify_font (font_desc);
387 private void fill_services_vbox (IdCard id_card)
390 var n_columns = id_card.services.length;
392 var services_table = new Table (n_columns, 2, false);
393 services_table.set_col_spacings (10);
394 services_table.set_row_spacings (10);
395 this.services_internal_vbox.add (services_table);
397 foreach (string service in id_card.services)
399 var label = new Label (service);
400 label.set_alignment (0, (float) 0.5);
402 var remove_button = new Button.from_stock (Stock.REMOVE);
404 var remove_button = new Button.from_stock (STOCK_REMOVE);
406 services_table.attach_defaults (label, 0, 1, i, i+1);
407 services_table.attach_defaults (remove_button, 1, 2, i, i+1);
410 this.services_internal_vbox.show_all ();
413 private void on_about_action ()
416 "Javier Jardón <jjardon@codethink.co.uk>",
417 "Sam Thursfield <samthursfield@codethink.co.uk>",
421 const string copyright = "Copyright 2011 JANET";
423 const string license =
425 Copyright (c) 2011, JANET(UK)
428 Redistribution and use in source and binary forms, with or without
429 modification, are permitted provided that the following conditions
432 1. Redistributions of source code must retain the above copyright
433 notice, this list of conditions and the following disclaimer.
435 2. Redistributions in binary form must reproduce the above copyright
436 notice, this list of conditions and the following disclaimer in the
437 documentation and/or other materials provided with the distribution.
439 3. Neither the name of JANET(UK) nor the names of its contributors
440 may be used to endorse or promote products derived from this software
441 without specific prior written permission.
443 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"
444 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
445 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
446 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
447 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
448 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
449 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
450 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
451 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
452 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
456 Gtk.show_about_dialog (this,
457 "comments", _("Moonshot project UI"),
458 "copyright", copyright,
459 "website", "http://www.project-moonshot.org/",
461 "website-label", _("Visit the Moonshot project web site"),
463 "translator-credits", _("translator-credits"),
468 private Gtk.ActionEntry[] create_actions() {
469 Gtk.ActionEntry[] actions = new Gtk.ActionEntry[0];
471 Gtk.ActionEntry filemenu = { "FileMenuAction",
476 Gtk.ActionEntry add = { "AddIdCardAction",
484 N_("Add a new ID Card"),
487 Gtk.ActionEntry quit = { "QuitAction",
495 N_("Quit the application"),
499 Gtk.ActionEntry helpmenu = { "HelpMenuAction",
504 Gtk.ActionEntry about = { "AboutAction",
512 N_("About this application"),
520 private void create_ui_manager ()
522 Gtk.ActionGroup action_group = new Gtk.ActionGroup ("GeneralActionGroup");
523 action_group.add_actions (create_actions (), this);
524 ui_manager.insert_action_group (action_group, 0);
527 ui_manager.add_ui_from_string (layout, -1);
531 stderr.printf ("%s\n", e.message);
533 ui_manager.ensure_update ();
536 private void build_ui()
538 create_ui_manager ();
540 this.search_entry = new Entry();
542 set_atk_name_description (search_entry, _("Search entry"), _("Search for a specific ID Card"));
543 this.search_entry.set_icon_from_pixbuf (EntryIconPosition.PRIMARY,
544 find_icon_sized ("edit-find-symbolic", Gtk.IconSize.MENU));
545 this.search_entry.set_icon_tooltip_text (EntryIconPosition.PRIMARY,
546 _("Search identity or service"));
547 this.search_entry.set_icon_sensitive (EntryIconPosition.PRIMARY, false);
549 this.search_entry.set_icon_from_pixbuf (EntryIconPosition.SECONDARY,
550 find_icon_sized ("edit-clear-symbolic", Gtk.IconSize.MENU));
551 this.search_entry.set_icon_tooltip_text (EntryIconPosition.SECONDARY,
552 _("Clear the current search"));
553 this.search_entry.set_icon_sensitive (EntryIconPosition.SECONDARY, false);
556 this.search_entry.icon_press.connect (search_entry_icon_press_cb);
557 this.search_entry.notify["text"].connect (search_entry_text_changed_cb);
558 this.search_entry.key_press_event.connect(search_entry_key_press_event_cb);
560 this.custom_vbox = new CustomVBox (false, 6);
562 var viewport = new Viewport (null, null);
563 viewport.set_border_width (6);
564 viewport.set_shadow_type (ShadowType.NONE);
565 viewport.add (custom_vbox);
566 var scroll = new ScrolledWindow (null, null);
567 scroll.set_policy (PolicyType.NEVER, PolicyType.AUTOMATIC);
568 scroll.set_shadow_type (ShadowType.IN);
569 scroll.add_with_viewport (viewport);
571 var vbox_left = new VBox (false, 0);
572 vbox_left.pack_start (search_entry, false, false, 6);
573 vbox_left.pack_start (scroll, true, true, 0);
574 vbox_left.set_size_request (WINDOW_WIDTH, 0);
576 var login_vbox_title = new Label (_("Login: "));
577 label_make_bold (login_vbox_title);
578 login_vbox_title.set_alignment (0, (float) 0.5);
579 var username_label = new Label (_("Username:"));
580 username_label.set_alignment (1, (float) 0.5);
581 this.username_entry = new Entry ();
582 var password_label = new Label (_("Password:"));
583 password_label.set_alignment (1, (float) 0.5);
584 this.password_entry = new Entry ();
585 password_entry.set_invisible_char ('*');
586 password_entry.set_visibility (false);
587 var remember_checkbutton = new CheckButton.with_label (_("Remember password"));
588 var login_table = new Table (3, 3, false);
589 login_table.set_col_spacings (10);
590 login_table.set_row_spacings (10);
591 login_table.attach_defaults (username_label, 0, 1, 0, 1);
592 login_table.attach_defaults (username_entry, 1, 2, 0, 1);
593 login_table.attach_defaults (password_label, 0, 1, 1, 2);
594 login_table.attach_defaults (password_entry, 1, 2, 1, 2);
595 login_table.attach_defaults (remember_checkbutton, 1, 2, 2, 3);
596 var login_vbox_alignment = new Alignment (0, 0, 0, 0);
597 login_vbox_alignment.set_padding (0, 0, 12, 0);
598 login_vbox_alignment.add (login_table);
599 var login_vbox = new VBox (false, 6);
600 login_vbox.pack_start (login_vbox_title, false, true, 0);
601 login_vbox.pack_start (login_vbox_alignment, false, true, 0);
603 var services_vbox_title = new Label (_("Services:"));
604 label_make_bold (services_vbox_title);
605 services_vbox_title.set_alignment (0, (float) 0.5);
606 var services_vbox_alignment = new Alignment (0, 0, 0, 0);
607 services_vbox_alignment.set_padding (0, 0, 12, 0);
608 this.services_internal_vbox = new VBox (true, 6);
609 services_vbox_alignment.add (services_internal_vbox);
610 var services_vbox = new VBox (false, 6);
611 services_vbox.pack_start (services_vbox_title, false, true, 0);
612 services_vbox.pack_start (services_vbox_alignment, false, true, 0);
614 this.vbox_rigth = new VBox (false, 18);
615 vbox_rigth.pack_start (login_vbox, false, true, 0);
616 vbox_rigth.pack_start (services_vbox, false, true, 0);
618 var hbox = new HBox (false, 12);
619 hbox.pack_start (vbox_left, false, false, 0);
620 hbox.pack_start (vbox_rigth, false, false, 0);
622 var main_vbox = new VBox (false, 0);
623 main_vbox.set_border_width (12);
624 var menubar = this.ui_manager.get_widget ("/MenuBar");
625 main_vbox.pack_start (menubar, false, false, 0);
626 main_vbox.pack_start (hbox, true, true, 0);
629 main_vbox.show_all();
630 this.vbox_rigth.hide ();
633 private void set_atk_name_description (Widget widget, string name, string description)
635 var atk_widget = widget.get_accessible ();
637 atk_widget.set_name (name);
638 atk_widget.set_description (description);
641 private void connect_signals()
643 this.destroy.connect (Gtk.main_quit);
646 private void init_ipc_server ()
649 /* Errors will currently be sent via g_log - ie. to an
650 * obtrusive message box, on Windows
652 this.ipc_server = MoonshotServer.get_instance ();
653 MoonshotServer.start (this);
656 var conn = DBus.Bus.get (DBus.BusType.SESSION);
657 dynamic DBus.Object bus = conn.get_object ("org.freedesktop.DBus",
658 "/org/freedesktop/DBus",
659 "org.freedesktop.DBus");
661 // try to register service in session bus
662 uint reply = bus.request_name ("org.janet.Moonshot", (uint) 0);
663 assert (reply == DBus.RequestNameReply.PRIMARY_OWNER);
665 this.ipc_server = new MoonshotServer (this);
666 conn.register_object ("/org/janet/moonshot", ipc_server);
671 stderr.printf ("%s\n", e.message);
676 public static int main(string[] args)
681 // Force specific theme settings on Windows without requiring a gtkrc file
682 Gtk.Settings settings = Gtk.Settings.get_default ();
683 settings.set_string_property ("gtk-theme-name", "ms-windows", "moonshot");
684 settings.set_long_property ("gtk-menu-images", 0, "moonshot");
687 Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
688 Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8");
689 Intl.textdomain (Config.GETTEXT_PACKAGE);
691 var window = new MainWindow();