Likely unstable.
[FinalKeyGui.git] / src / fkgui / MainWin.java
1 package fkgui;
2
3
4 import  java.util.prefs.*;
5 import java.awt.*;
6 import java.awt.event.ActionEvent;
7 import java.awt.event.ActionListener;
8
9 import javax.swing.UIManager;
10 import javax.swing.UnsupportedLookAndFeelException;
11
12 import org.eclipse.jface.viewers.DoubleClickEvent;
13 import org.eclipse.jface.viewers.IDoubleClickListener;
14 import org.eclipse.jface.viewers.ISelectionChangedListener;
15 import org.eclipse.jface.viewers.ListViewer;
16 import org.eclipse.jface.viewers.SelectionChangedEvent;
17 import org.eclipse.jface.viewers.StructuredSelection;
18 import org.eclipse.swt.widgets.Display;
19 import org.eclipse.swt.widgets.MessageBox;
20 import org.eclipse.swt.widgets.Shell;
21 import org.eclipse.swt.widgets.Button;
22 import org.eclipse.swt.SWT;
23 import org.eclipse.swt.events.SelectionAdapter;
24 import org.eclipse.swt.events.SelectionEvent;
25 import org.eclipse.swt.events.ShellEvent;
26 import org.eclipse.swt.events.ShellListener;
27 import org.eclipse.swt.widgets.Text;
28 import org.eclipse.swt.widgets.Label;
29 import org.eclipse.swt.widgets.Control;
30 import org.eclipse.wb.swt.SWTResourceManager;
31
32 import fkgui.FkManager.Account;
33 import fkgui.SerialWorker.SerialState;
34 import fkgui.UpdateChecker.AutoUpdaterResultListener;
35
36 import org.eclipse.swt.widgets.TabFolder;
37 import org.eclipse.swt.widgets.TabItem;
38 import org.eclipse.swt.widgets.Composite;
39 import org.eclipse.swt.layout.FormLayout;
40 import org.eclipse.swt.layout.FormData;
41 import org.eclipse.swt.layout.FormAttachment;
42 import org.eclipse.swt.layout.FillLayout;
43
44
45 public class MainWin implements ConsoleMsg, AutoUpdaterResultListener {
46
47         protected Shell shell;
48         private Text txtPsw;
49         public TrayIcon trayIcon;
50         public PopupMenu popup;
51         public MenuItem showMain;
52         public MenuItem hideMain;
53
54         public Text txtLog;
55         public Button btnConnect;
56         public Button chkAutoHide;
57         public Label lblPort;
58         public Label lblPassword;
59         
60         public Animation animation;
61         
62         public TabFolder tabFolder;
63
64         private Text txtDev;
65         Preferences prefs;
66         MainWin mySelf;
67         private SerialState lastState = SerialState.Disconnected;
68         
69         SerialWorker fkSerial;
70         private boolean sysTrayIconVisible;
71
72         
73         static final String PREF_PORT ="lastUsedPortPref";
74         static final String DEFAULT_DEVICE = "/dev/FinalKey";
75         static final String PREF_AUTOHIDE = "hideMainWinAfterConnect";
76         public Composite cmpConnect;
77         private Composite cmpAccounts;
78         ListViewer lstAccounts;
79         Label lblNumFree;
80         Button btnNewAccoount;
81  
82         
83         /**
84          * Launch the application.
85          * @param args
86          */
87         public static void main(String[] args) {
88
89                 try {
90                         MainWin window = new MainWin();
91                         window.open();
92                 } catch (Exception e) {
93                         e.printStackTrace();
94                 }
95                 
96         }
97
98         /**
99          * Open the window.
100          */
101         public void open() {
102                 Display display = Display.getDefault();
103                 createContents();
104                 shell.open();
105                 shell.layout();
106                 createSysTrayIcon();
107                 serialEvent(SerialState.Disconnected);
108                 new Thread(new UpdateChecker(this)).start();
109
110                 while (!shell.isDisposed()) {
111                         if (!display.readAndDispatch()) {
112                                 display.sleep();                                
113                         }
114                 }
115         }
116         
117         public void log( String str )
118         {
119                 txtLog.append(str+"\n");
120                 if( tabFolder.getSelectionIndex() == 0 )
121                 {
122                         txtLog.redraw();
123                         shell.redraw();
124                 }
125                 System.out.println(str);
126
127         }
128
129         /**
130          * Create a systemTray icon
131          */
132         private void createSysTrayIcon()
133         {
134                 sysTrayIconVisible=true;
135         //Check the SystemTray is supported
136         if (!SystemTray.isSupported()) {
137             log("SystemTray is not supported, app is useless");
138             return;
139         }
140         
141         try {
142                         UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
143                 } catch (Exception e1) {
144                         e1.printStackTrace();
145                 } 
146
147         popup = new PopupMenu();
148         trayIcon =
149                 new TrayIcon(Toolkit.getDefaultToolkit().createImage(getClass().getResource("gfx/finalkey.png")));
150         trayIcon.setToolTip("The Final Key - Hardware password manager");
151         trayIcon.setImageAutoSize(true);
152         final SystemTray tray = SystemTray.getSystemTray();
153        
154         // Create a pop-up menu components
155         showMain = new MenuItem("Show FinalKey");
156         hideMain = new MenuItem("Hide FinalKey");
157
158         showMain.addActionListener(new ActionListener() {
159                         @Override
160                         public void actionPerformed(ActionEvent e) {
161                                 Display.getDefault().syncExec( new Runnable(){
162                                         
163                                         public void run()
164                                         {
165                                                 showFromTray();
166                                         }
167                                 } );
168                         }
169                                 
170                 });
171         
172         hideMain.addActionListener(new ActionListener() {
173                         @Override
174                         public void actionPerformed(ActionEvent e) {
175                                 Display.getDefault().syncExec( new Runnable(){
176                                         
177                                         public void run()
178                                         {
179                                                 hideToTray();
180                                         }
181                                 } );
182                         }
183                                 
184                 });
185
186         clearSystray();
187
188
189         trayIcon.setPopupMenu(popup);
190        
191         try {
192             tray.add(trayIcon);
193         } catch (AWTException e) {
194                 log("TrayIcon could not be added.");
195         }       
196         
197         }
198         
199         private void hideToTray()
200         {
201                 popup.remove(0);
202                 popup.insert(showMain, 0);
203                 shell.setVisible(false);
204         }
205         
206         private void showFromTray()
207         {
208                 popup.remove(0);
209                 popup.insert(hideMain, 0);
210                 shell.setVisible(true);
211                 shell.forceActive();
212         }
213         
214         private void destroySysTrayIcon()
215         {
216                 sysTrayIconVisible=false;
217                 SystemTray.getSystemTray().remove(trayIcon);
218         }
219         
220         private void clearSystray() {
221                         popup.removeAll();
222                 //Add components to pop-up menu
223                         if(shell.isVisible()==true)
224                         {
225                                 popup.add(hideMain);
226                         } else {
227                                 popup.add(showMain);
228                         }
229                 popup.addSeparator();
230         }
231
232         public void shutDownApp()
233         {
234                 if(fkSerial != null)
235                 {
236                         fkSerial.disconnect();
237                 }
238                 if(sysTrayIconVisible == true)
239                 {
240                         destroySysTrayIcon();
241                 }
242                 System.exit(0);
243         }
244         
245         /**
246          * Create contents of the window.
247          */
248         protected void createContents() {
249                 shell = new Shell();
250                 shell.setImage(SWTResourceManager.getImage(MainWin.class, "/fkgui/gfx/finalkey.png"));
251                 shell.setSize(711, 655);
252                 shell.setText("Final Key (Not connected)");
253
254                 
255                 prefs = Preferences.userNodeForPackage(this.getClass());
256                 
257
258                 mySelf = this;
259                 shell.setLayout(new FillLayout(SWT.HORIZONTAL));
260                 
261                 tabFolder = new TabFolder(shell, SWT.NONE);
262                 tabFolder.setBackground(SWTResourceManager.getColor(SWT.COLOR_WIDGET_LIGHT_SHADOW));
263                 
264                 TabItem tbtmConnection = new TabItem(tabFolder, SWT.NONE);
265                 tbtmConnection.setText("Connection");
266                 
267                 cmpConnect = new Composite(tabFolder, SWT.BORDER);
268                 tbtmConnection.setControl(cmpConnect);
269                 cmpConnect.setLayout(new FormLayout());
270                 
271
272                 btnConnect = new Button(cmpConnect, SWT.CENTER);
273                 btnConnect.setImage( SWTResourceManager.getImage(MainWin.class, "/fkgui/gfx/lightning.png") );
274                 FormData fd_btnConnect = new FormData();
275                 fd_btnConnect.left = new FormAttachment(100, -125);
276                 fd_btnConnect.right = new FormAttachment(100, -10);
277                 btnConnect.setLayoutData(fd_btnConnect);
278
279                 btnConnect.addSelectionListener(new SelectionAdapter() {
280                         public void widgetSelected(SelectionEvent e) {
281                                 
282                                 
283                                 if( fkSerial!=null && fkSerial.state == SerialState.Connected )
284                                 {
285                                         fkSerial.disconnect();
286                                 } else {
287                                         
288                                         prefs.putBoolean(PREF_AUTOHIDE, chkAutoHide.getSelection() );
289
290                                         fkSerial = new SerialWorker(mySelf);
291                                         prefs.put(PREF_PORT, txtDev.getText() );
292                                         fkSerial.connect(txtDev.getText(),txtPsw.getText());
293                                         txtPsw.setText("");
294                                 }
295                         }
296                 });
297                 btnConnect.setText("Connect");
298                 
299                 txtPsw = new Text(cmpConnect, SWT.BORDER | SWT.PASSWORD);
300                 fd_btnConnect.bottom = new FormAttachment(txtPsw, 0, SWT.BOTTOM);
301                 FormData fd_txtPsw = new FormData();
302                 fd_txtPsw.bottom = new FormAttachment(0, 52);
303                 fd_txtPsw.right = new FormAttachment(0, 501);
304                 fd_txtPsw.top = new FormAttachment(0, 29);
305                 fd_txtPsw.left = new FormAttachment(0, 102);
306                 txtPsw.setLayoutData(fd_txtPsw);
307                 txtPsw.setFocus();
308                 
309                 txtLog = new Text(cmpConnect, SWT.BORDER | SWT.V_SCROLL | SWT.MULTI);
310                 FormData fd_txtLog = new FormData();
311                 fd_txtLog.left = new FormAttachment(0, 10);
312                 fd_txtLog.right = new FormAttachment(100, -10);
313                 fd_txtLog.bottom = new FormAttachment(100, -10);
314                 fd_txtLog.top = new FormAttachment(0, 58);
315                 txtLog.setLayoutData(fd_txtLog);
316                 txtLog.setEditable(false);
317                 
318                 lblPort = new Label(cmpConnect, SWT.NONE);
319                 fd_btnConnect.top = new FormAttachment(lblPort, 0, SWT.TOP);
320                 FormData fd_lblPort = new FormData();
321                 fd_lblPort.right = new FormAttachment(0, 86);
322                 fd_lblPort.top = new FormAttachment(0);
323                 fd_lblPort.left = new FormAttachment(0, 10);
324                 lblPort.setLayoutData(fd_lblPort);
325                 lblPort.setText("Port");
326                 
327                 txtDev = new Text(cmpConnect, SWT.BORDER);
328                 FormData fd_txtDev = new FormData();
329                 fd_txtDev.bottom = new FormAttachment(0, 23);
330                 fd_txtDev.right = new FormAttachment(0, 256);
331                 fd_txtDev.top = new FormAttachment(0);
332                 fd_txtDev.left = new FormAttachment(0, 102);
333                 txtDev.setLayoutData(fd_txtDev);
334                 txtDev.setFont(SWTResourceManager.getFont("Cantarell", 9, SWT.NORMAL));
335                 txtDev.setText( prefs.get(PREF_PORT, DEFAULT_DEVICE));
336                 lblPassword = new Label(cmpConnect, SWT.NONE);
337                 FormData fd_lblPassword = new FormData();
338                 fd_lblPassword.right = new FormAttachment(0, 95);
339                 fd_lblPassword.top = new FormAttachment(0, 29);
340                 fd_lblPassword.left = new FormAttachment(0, 10);
341                 lblPassword.setLayoutData(fd_lblPassword);
342                 lblPassword.setText("Password");
343                 
344                 chkAutoHide = new Button(cmpConnect, SWT.CHECK);
345                 FormData fd_chkAutoHide = new FormData();
346                 fd_chkAutoHide.right = new FormAttachment(0, 501);
347                 fd_chkAutoHide.top = new FormAttachment(0);
348                 fd_chkAutoHide.left = new FormAttachment(0, 262);
349                 chkAutoHide.setLayoutData(fd_chkAutoHide);
350                 chkAutoHide.setText("Hide after connection");
351                 
352                 chkAutoHide.setSelection( prefs.getBoolean(PREF_AUTOHIDE, false)) ;
353                 
354                 animation = new Animation(cmpConnect, SWT.NONE, 4);
355
356                 FormData fd_animation = new FormData();
357                 fd_animation.right = new FormAttachment(0, 86);
358                 fd_animation.top = new FormAttachment(0);
359                 fd_animation.left = new FormAttachment(0, 10);          
360                 
361                 animation.setLayoutData(fd_animation);
362
363
364                 
365                 animation.setVisible(false);
366                 animation.addFrame( SWTResourceManager.getImage(MainWin.class, "/fkgui/gfx/finalkey1.png") );
367                 animation.addFrame( SWTResourceManager.getImage(MainWin.class, "/fkgui/gfx/finalkey2.png") );
368                 animation.setPlaying(false);
369                 cmpConnect.setTabList(new Control[]{txtPsw, btnConnect});
370                 
371         
372                 
373                 log("Type your password and press connect.\n----------\n");
374
375
376                 shell.addShellListener( new ShellListener() {
377                         
378                         public void shellIconified(ShellEvent e) {
379                                 // TODO Auto-generated method stub
380
381                         }
382
383                         public void shellDeiconified(ShellEvent e) {
384                                 // TODO Auto-generated method stub
385                                 
386                         }
387                         
388                         public void shellDeactivated(ShellEvent e) {
389                                 // TODO Auto-generated method stub
390                         }
391                         
392                         public void shellClosed(ShellEvent e) {
393                                 shutDownApp();
394                         }
395                         
396                         public void shellActivated(ShellEvent e) {
397                                 // TODO Auto-generated method stub
398                                 
399                         }
400                 } );
401                 
402
403
404         }
405
406         @Override
407         public void updateAccountList()
408         {
409                 int free=256;
410                 clearSystray();
411                 lstAccounts.getList().removeAll();
412                 
413                 for( FkManager.Account a : FkManager.getInstance().getList() )
414                 {
415                         free--;
416                         lstAccounts.add( a );
417                                                         
418                         Menu menu = new Menu(a.name+" ["+a.num+"]");
419                         MenuItem both = new MenuItem("User + Pass");
420                         MenuItem usr = new MenuItem("User");
421                         MenuItem psw = new MenuItem("Pass");
422                         menu.add(both);
423                         menu.add(usr);
424                         menu.add(psw);
425
426
427                         both.addActionListener(FkManager.getInstance());
428                         both.setActionCommand( "%"+a.num );
429
430
431
432                         psw.addActionListener(FkManager.getInstance()); 
433                         psw.setActionCommand( "p"+a.num);
434
435
436                         usr.addActionListener(FkManager.getInstance()); 
437                         usr.setActionCommand( "u"+a.num );
438
439                         popup.add(menu);
440                 }
441                 
442                 lblNumFree.setText(" "+free+" of 256 free.");
443                 if( free == 0 )
444                 {
445                         btnNewAccoount.setVisible(false);
446                 } else {
447                         btnNewAccoount.setVisible(true);
448                 }
449                 
450         }
451
452         @Override
453         public void serialEvent(SerialState state) {
454                 switch(state)
455                 {
456                 case Connected:
457                         shell.setText("Final Key (Connected)");
458                         
459                         animation.setVisible(false);
460                         animation.setPlaying(false);
461
462
463                         btnConnect.setText("Disconnect");
464                         btnConnect.setVisible(true);
465                         
466                         //Should we hide?
467                         if( prefs.getBoolean(PREF_AUTOHIDE, false) == true)
468                         {
469                                 hideToTray();
470                         }
471                         
472                         addAccountsTab();
473                         
474                         
475                         tabFolder.setSelection(1);
476                         
477                         updateAccountList();
478                         
479                         
480                         int numAccounts=FkManager.getInstance().getList().size();
481                         if( numAccounts>0 )
482                         {
483                                 trayIcon.displayMessage("FinalKey", numAccounts + " account"+(( numAccounts >1)?"s":"")+" ready.", 
484                                     TrayIcon.MessageType.INFO);
485                         }
486
487                         
488                         log("* Connected *");
489                         break;
490                 case Connecting:
491                         shell.setText("Final Key (Connecting...)");
492                         animation.setVisible(true);
493                         animation.setPlaying(true);
494
495                         txtPsw.setVisible(false);
496                         txtDev.setVisible(false);
497                         btnConnect.setVisible(false);
498                         lblPort.setVisible(false);
499                         lblPassword.setVisible(false);
500                         chkAutoHide.setVisible(false);
501                         break;
502                 case Disconnected:
503                         fkSerial=null;
504                         animation.setVisible(false);
505                         animation.setPlaying(false);
506
507                         remAccountsTab();
508                         
509                         tabFolder.setSelection(0);
510
511                         shell.setText("Final Key (Not connected)");
512                         txtPsw.setVisible(true);
513                         txtDev.setVisible(true);
514                         btnConnect.setText("Connect");
515                         btnConnect.setVisible(true);
516                         lblPort.setVisible(true);
517                         lblPassword.setVisible(true);
518                         chkAutoHide.setVisible(true);
519                         clearSystray();
520                         if(lastState != state)
521                         {
522                                 log("* Disconnected *");
523                         }
524                         break;
525                 
526                 case Working:
527                         animation.setPlaying(false);
528                         animation.setVisible(false);
529                         break;
530                         
531                 default:
532                         break;
533                 }
534                 lastState=state;
535                 cmpConnect.layout();
536         }
537
538         private void remAccountsTab() {
539                 if( tabFolder.getItemCount() > 1 )
540                 {
541                         tabFolder.getItem(1).dispose();
542                 }
543                 
544         }
545
546         private void addAccountsTab() {
547                 TabItem tbtmAccounts = new TabItem(tabFolder, SWT.NONE);
548                 tbtmAccounts.setText("Accounts");
549                 
550                 cmpAccounts = new Composite(tabFolder, SWT.BORDER);
551                 tbtmAccounts.setControl(cmpAccounts);
552                 cmpAccounts.setLayout(new FormLayout());
553                 
554                 btnNewAccoount = new Button(cmpAccounts, SWT.NONE);
555                 btnNewAccoount.setImage(SWTResourceManager.getImage(MainWin.class, "/fkgui/gfx/new.png"));
556                 btnNewAccoount.addSelectionListener(new SelectionAdapter() {
557                         @Override
558                         public void widgetSelected(SelectionEvent e) {
559                                 NewAccountDialog dialog = new NewAccountDialog(shell, shell.getStyle() );
560                                 shell.setEnabled(false);
561                                 dialog.open();
562                                 shell.setEnabled(true);
563                                 updateAccountList();
564                                 
565                         }
566                 });
567                 FormData fd_btnNewAccoount = new FormData();
568                 fd_btnNewAccoount.left = new FormAttachment(0, 530);
569                 fd_btnNewAccoount.right = new FormAttachment(100, -10);
570                 fd_btnNewAccoount.bottom = new FormAttachment(100, -10);
571                 btnNewAccoount.setLayoutData(fd_btnNewAccoount);
572                 btnNewAccoount.setText("New Account");
573                 
574                 lblNumFree = new Label(cmpAccounts, SWT.NONE);
575                 lblNumFree.setText("Hello World!");
576                 
577                 FormData fd_lblNumFree = new FormData();
578                 fd_lblNumFree.left = new FormAttachment(0,0);
579                 fd_lblNumFree.bottom = new FormAttachment(100,-10);
580                 lblNumFree.setLayoutData(fd_lblNumFree);
581                 
582                 
583                 lstAccounts = new ListViewer(cmpAccounts, SWT.BORDER | SWT.V_SCROLL);
584                 FormData fd_lstAccounts = new FormData();
585                 fd_lstAccounts.bottom = new FormAttachment(btnNewAccoount, -6);
586                 fd_lstAccounts.top = new FormAttachment(0, 10);
587                 fd_lstAccounts.left = new FormAttachment(0, 10);
588                 fd_lstAccounts.right = new FormAttachment(100, -10);
589                 
590
591                 //lstAccounts.setLayoutData(fd_lstAccounts);
592                 lstAccounts.getControl().setLayoutData(fd_lstAccounts);
593                 lstAccounts.addDoubleClickListener( new IDoubleClickListener() {
594                         
595                         @Override
596                         public void doubleClick(DoubleClickEvent arg0) {
597                                 // TODO Auto-generated method stub
598                                 StructuredSelection selection = (StructuredSelection) arg0.getSelection();
599                                 if( !selection.isEmpty() )
600                                 {
601                                         Account acc = (Account)selection.getFirstElement();
602                                         TriggerDialog diag = new TriggerDialog(shell, shell.getStyle(), acc, mySelf );
603
604                                         shell.setMinimized(true);
605                                         shell.setEnabled(false);
606                                         if( !((Boolean)diag.open()) )
607                                         {
608                                                 shell.setMinimized(false);
609                                         }
610                                         
611                                         shell.setEnabled(true);
612                                 } else {
613                                         System.out.println("Selected nothing.");
614                                 }
615                                 
616                                 
617                         }
618                 });
619                 
620                 
621                                 
622         }
623
624
625         @Override
626         public void updateCheckFinished(AutoUpdaterResultEvent event) {
627                 switch(event.result)
628                 {
629                 case CHECK_FAILED:
630                         System.out.println("Trouble checking for updates.");
631                         break;
632                 case NO_UPDATE:
633                         System.out.println("No update avaiable at this time.");
634                         break;
635                 case UPDATE_AVAILABLE:
636                         MessageBox dialog = new MessageBox(shell, SWT.ICON_INFORMATION | SWT.OK);
637                         dialog.setText("FinalKey GUI Version "+event.version+" available.");
638                         dialog.setMessage("There's a new version of FinalKey GUI available.\nGo to http://cyberstalker.dk/finalkey/gui/ to download.\n\nNews:\n"+event.message);
639                         dialog.open();  
640                         break;
641                 }
642                 
643         }
644
645
646 }