/* * Universal Password Manager * Copyright (C) 2005-2013 Adrian Smith * * This file is part of Universal Password Manager. * * Universal Password Manager is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Universal Password Manager is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Universal Password Manager; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com._17od.upm.gui; import java.awt.Desktop; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.awt.Color; import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.security.GeneralSecurityException; import javax.crypto.IllegalBlockSizeException; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JTextField; import javax.swing.JToolBar; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.border.EmptyBorder; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.apache.commons.validator.routines.UrlValidator; import com._17od.upm.crypto.InvalidPasswordException; import com._17od.upm.database.AccountInformation; import com._17od.upm.database.ProblemReadingDatabaseFile; import com._17od.upm.platformspecific.PlatformSpecificCode; import com._17od.upm.util.Preferences; import com._17od.upm.util.Translator; import com._17od.upm.util.Util; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Rectangle; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.Arrays; /** * This is the main application entry class */ public class MainWindow extends JFrame implements ActionListener { private static final long serialVersionUID = 1L; private static final String applicationName = "Universal Password Manager"; public static final String NEW_DATABASE_TXT = "newDatabaseMenuItem"; public static final String OPEN_DATABASE_TXT = "openDatabaseMenuItem"; public static final String OPEN_DATABASE_FROM_URL_TXT = "openDatabaseFromURLMenuItem"; public static final String SYNC_DATABASE_TXT = "syncWithRemoteDatabaseMenuItem"; public static final String CHANGE_MASTER_PASSWORD_TXT = "changeMasterPasswordMenuItem"; public static final String DATABASE_PROPERTIES_TXT = "databasePropertiesMenuItem"; public static final String ADD_ACCOUNT_TXT = "addAccountMenuItem"; public static final String EDIT_ACCOUNT_TXT = "editAccountMenuItem"; public static final String DELETE_ACCOUNT_TXT = "deleteAccountMenuItem"; public static final String VIEW_ACCOUNT_TXT = "viewAccountMenuItem"; public static final String COPY_USERNAME_TXT = "copyUsernameMenuItem"; public static final String COPY_PASSWORD_TXT = "copyPasswordMenuItem"; public static final String LAUNCH_URL_TXT = "launchURLMenuItem"; public static final String OPTIONS_TXT = "optionsMenuItem"; public static final String ABOUT_TXT = "aboutMenuItem"; public static final String RESET_SEARCH_TXT = "resetSearchMenuItem"; public static final String EXIT_TXT = "exitMenuItem"; public static final String EXPORT_TXT = "exportMenuItem"; public static final String IMPORT_TXT = "importMenuItem"; public static final String LOCK_TIMER_TXT = "lock"; private JButton addAccountButton; private JButton editAccountButton; private JButton deleteAccountButton; private JButton copyUsernameButton; private JButton copyPasswordButton; private JButton launchURLButton; private JButton optionsButton; private JButton syncDatabaseButton; private JTextField searchField; private JButton resetSearchButton; private JLabel searchIcon; private JMenu databaseMenu; private JMenuItem newDatabaseMenuItem; private JMenuItem openDatabaseMenuItem; private JMenuItem openDatabaseFromURLMenuItem; private JMenuItem syncWithRemoteDatabaseMenuItem; private JMenuItem changeMasterPasswordMenuItem; private JMenuItem databasePropertiesMenuItem; private JMenuItem exitMenuItem; private JMenu helpMenu; private JMenuItem aboutMenuItem; private JMenu accountMenu; private JMenuItem addAccountMenuItem; private JMenuItem editAccountMenuItem; private JMenuItem deleteAccountMenuItem; private JMenuItem viewAccountMenuItem; private JMenuItem copyUsernameMenuItem; private JMenuItem copyPasswordMenuItem; private JMenuItem launchURLMenuItem; private JMenuItem exportMenuItem; private JMenuItem importMenuItem; private JList accountsListview; private JLabel statusBar = new JLabel(" "); private JPanel databaseFileChangedPanel; public static MainWindow AppWindow; private DatabaseActions dbActions; public MainWindow(String title) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException, IllegalBlockSizeException, IOException, GeneralSecurityException, ProblemReadingDatabaseFile { super(title); setIconImage(Util.loadImage("upm.gif").getImage()); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); PlatformSpecificCode.getInstance().initialiseApplication(this); dbActions = new DatabaseActions(this); // Set up the content pane. addComponentsToPane(); // Add listener to store current position and size on closing this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { storeWindowBounds(); try { Preferences.save(); } catch (IOException ex) { // Not much we can do at this point ex.printStackTrace(); } } }); // Display the window. pack(); setLocationRelativeTo(null); boolean restore = Preferences.get(Preferences.ApplicationOptions.REMEMBER_WINDOW_POSITION, "false") .equals("true"); if (restore) { restoreWindowBounds(); } Boolean appAlwaysonTop = new Boolean( Preferences.get(Preferences.ApplicationOptions.MAINWINDOW_ALWAYS_ON_TOP, "false")); setAlwaysOnTop(appAlwaysonTop.booleanValue()); setVisible(true); try { // Load the startup database if it's configured String db = Preferences.get(Preferences.ApplicationOptions.DB_TO_LOAD_ON_STARTUP); if (db != null && !db.equals("")) { File dbFile = new File(db); if (!dbFile.exists()) { dbActions.errorHandler(new Exception(Translator.translate("dbDoesNotExist", db))); } else { dbActions.openDatabase(db); } } } catch (Exception e) { dbActions.errorHandler(e); } // Give the search field focus // I'm using requestFocusInWindow() rathar than requestFocus() // because the javadocs recommend it searchField.requestFocusInWindow(); } public static void setAppAlwaysonTop(boolean val) { AppWindow.setAlwaysOnTop(val); // AppWindow.revalidate(); } public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { try { // Use the System look and feel Preferences.load(); Translator.initialise(); Double jvmVersion = new Double(System.getProperty("java.specification.version")); if (jvmVersion.doubleValue() < 1.4) { JOptionPane.showMessageDialog(null, Translator.translate("requireJava14"), Translator.translate("problem"), JOptionPane.ERROR_MESSAGE); System.exit(1); } else { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); AppWindow = new MainWindow(applicationName); } } catch (Exception e) { e.printStackTrace(); } } }); } private void addComponentsToPane() { // Ensure the layout manager is a BorderLayout if (!(getContentPane().getLayout() instanceof GridBagLayout)) { getContentPane().setLayout(new GridBagLayout()); } // Create the menubar setJMenuBar(createMenuBar()); GridBagConstraints c = new GridBagConstraints(); // The toolbar Row c.gridx = 0; c.gridy = 0; c.anchor = GridBagConstraints.FIRST_LINE_START; c.insets = new Insets(0, 0, 0, 0); c.weightx = 0; c.weighty = 0; c.gridwidth = 3; c.fill = GridBagConstraints.HORIZONTAL; Component toolbar = createToolBar(); getContentPane().add(toolbar, c); // Keep the frame background color consistent getContentPane().setBackground(toolbar.getBackground()); // The seperator Row c.gridx = 0; c.gridy = 1; c.anchor = GridBagConstraints.LINE_START; c.insets = new Insets(0, 0, 0, 0); c.weightx = 1; c.weighty = 0; c.gridwidth = 3; c.fill = GridBagConstraints.HORIZONTAL; getContentPane().add(new JSeparator(), c); // The search field row searchIcon = new JLabel(Util.loadImage("search.gif")); searchIcon.setDisabledIcon(Util.loadImage("search_d.gif")); searchIcon.setEnabled(false); c.gridx = 0; c.gridy = 2; c.anchor = GridBagConstraints.LINE_START; c.insets = new Insets(5, 1, 5, 1); c.weightx = 0; c.weighty = 0; c.gridwidth = 1; c.fill = GridBagConstraints.NONE; getContentPane().add(searchIcon, c); searchField = new JTextField(15); searchField.setEnabled(false); searchField.setMinimumSize(searchField.getPreferredSize()); searchField.getDocument().addDocumentListener(new DocumentListener() { public void changedUpdate(DocumentEvent e) { // This method never seems to be called } public void insertUpdate(DocumentEvent e) { dbActions.filter(); } public void removeUpdate(DocumentEvent e) { dbActions.filter(); } }); searchField.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { dbActions.resetSearch(); } else if (e.getKeyCode() == KeyEvent.VK_ENTER) { // If the user hits the enter key in the search field and // there's only one item // in the listview then open that item (this code assumes // that the one item in // the listview has already been selected. this is done // automatically in the // DatabaseActions.filter() method) if (accountsListview.getModel().getSize() == 1) { viewAccountMenuItem.doClick(); } } } }); c.gridx = 1; c.gridy = 2; c.anchor = GridBagConstraints.LINE_START; c.insets = new Insets(5, 1, 5, 1); c.weightx = 0; c.weighty = 0; c.gridwidth = 1; c.fill = GridBagConstraints.NONE; getContentPane().add(searchField, c); resetSearchButton = new JButton(Util.loadImage("stop.gif")); resetSearchButton.setDisabledIcon(Util.loadImage("stop_d.gif")); resetSearchButton.setEnabled(false); resetSearchButton.setToolTipText(Translator.translate(RESET_SEARCH_TXT)); resetSearchButton.setActionCommand(RESET_SEARCH_TXT); resetSearchButton.addActionListener(this); resetSearchButton.setBorder(BorderFactory.createEmptyBorder()); resetSearchButton.setFocusable(false); c.gridx = 2; c.gridy = 2; c.anchor = GridBagConstraints.LINE_START; c.insets = new Insets(5, 1, 5, 1); c.weightx = 1; c.weighty = 0; c.gridwidth = 1; c.fill = GridBagConstraints.NONE; getContentPane().add(resetSearchButton, c); // The accounts listview row accountsListview = new JList(); accountsListview.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); accountsListview.setSelectedIndex(0); accountsListview.setVisibleRowCount(10); accountsListview.setModel(new SortedListModel()); JScrollPane accountsScrollList = new JScrollPane(accountsListview, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); accountsListview.addFocusListener(new FocusAdapter() { public void focusGained(FocusEvent e) { // If the listview gets focus, there is one ore more items in // the listview and there is nothing // already selected, then select the first item in the list if (accountsListview.getModel().getSize() > 0 && accountsListview.getSelectedIndex() == -1) { accountsListview.setSelectionInterval(0, 0); } } }); accountsListview.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { dbActions.setButtonState(); } }); accountsListview.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { viewAccountMenuItem.doClick(); } } }); accountsListview.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { viewAccountMenuItem.doClick(); } } }); // Create a shortcut to delete account functionality with DEL(delete) // key accountsListview.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_DELETE) { try { dbActions.reloadDatabaseBefore(new DeleteAccountAction()); } catch (InvalidPasswordException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (ProblemReadingDatabaseFile e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } } }); c.gridx = 0; c.gridy = 3; c.anchor = GridBagConstraints.CENTER; c.insets = new Insets(0, 1, 1, 1); c.weightx = 1; c.weighty = 1; c.gridwidth = 3; c.fill = GridBagConstraints.BOTH; getContentPane().add(accountsScrollList, c); // The "File Changed" panel c.gridx = 0; c.gridy = 4; c.anchor = GridBagConstraints.CENTER; c.insets = new Insets(0, 1, 0, 1); c.ipadx = 3; c.ipady = 3; c.weightx = 0; c.weighty = 0; c.gridwidth = 3; c.fill = GridBagConstraints.BOTH; databaseFileChangedPanel = new JPanel(); databaseFileChangedPanel.setLayout(new BoxLayout(databaseFileChangedPanel, BoxLayout.X_AXIS)); databaseFileChangedPanel.setBackground(new Color(249, 172, 60)); databaseFileChangedPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); JLabel fileChangedLabel = new JLabel("Database file changed"); fileChangedLabel.setAlignmentX(LEFT_ALIGNMENT); databaseFileChangedPanel.add(fileChangedLabel); databaseFileChangedPanel.add(Box.createHorizontalGlue()); JButton reloadButton = new JButton("Reload"); reloadButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { dbActions.reloadDatabaseFromDisk(); } catch (Exception ex) { dbActions.errorHandler(ex); } } }); databaseFileChangedPanel.add(reloadButton); databaseFileChangedPanel.setVisible(false); getContentPane().add(databaseFileChangedPanel, c); // Add the statusbar c.gridx = 0; c.gridy = 5; c.anchor = GridBagConstraints.CENTER; c.insets = new Insets(0, 1, 1, 1); c.weightx = 1; c.weighty = 0; c.gridwidth = 3; c.fill = GridBagConstraints.HORIZONTAL; getContentPane().add(statusBar, c); } public void setFileChangedPanelVisible(boolean visible) { databaseFileChangedPanel.setVisible(visible); } private JToolBar createToolBar() { JToolBar toolbar = new JToolBar(); toolbar.setFloatable(false); toolbar.setRollover(true); // The "Add Account" button addAccountButton = new JButton(); addAccountButton.setToolTipText(Translator.translate(ADD_ACCOUNT_TXT)); addAccountButton.setIcon(Util.loadImage("add_account.gif")); addAccountButton.setDisabledIcon(Util.loadImage("add_account_d.gif")); ; addAccountButton.addActionListener(this); addAccountButton.setEnabled(false); addAccountButton.setActionCommand(ADD_ACCOUNT_TXT); toolbar.add(addAccountButton); // The "Edit Account" button editAccountButton = new JButton(); editAccountButton.setToolTipText(Translator.translate(EDIT_ACCOUNT_TXT)); editAccountButton.setIcon(Util.loadImage("edit_account.gif")); editAccountButton.setDisabledIcon(Util.loadImage("edit_account_d.gif")); ; editAccountButton.addActionListener(this); editAccountButton.setEnabled(false); editAccountButton.setActionCommand(EDIT_ACCOUNT_TXT); toolbar.add(editAccountButton); // The "Delete Account" button deleteAccountButton = new JButton(); deleteAccountButton.setToolTipText(Translator.translate(DELETE_ACCOUNT_TXT)); deleteAccountButton.setIcon(Util.loadImage("delete_account.gif")); deleteAccountButton.setDisabledIcon(Util.loadImage("delete_account_d.gif")); ; deleteAccountButton.addActionListener(this); deleteAccountButton.setEnabled(false); deleteAccountButton.setActionCommand(DELETE_ACCOUNT_TXT); toolbar.add(deleteAccountButton); toolbar.addSeparator(); // The "Copy Username" button copyUsernameButton = new JButton(); copyUsernameButton.setToolTipText(Translator.translate(COPY_USERNAME_TXT)); copyUsernameButton.setIcon(Util.loadImage("copy_username.gif")); copyUsernameButton.setDisabledIcon(Util.loadImage("copy_username_d.gif")); ; copyUsernameButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { copyUsernameToClipboard(); } }); copyUsernameButton.setEnabled(false); toolbar.add(copyUsernameButton); // The "Copy Password" button copyPasswordButton = new JButton(); copyPasswordButton.setToolTipText(Translator.translate(COPY_PASSWORD_TXT)); copyPasswordButton.setIcon(Util.loadImage("copy_password.gif")); copyPasswordButton.setDisabledIcon(Util.loadImage("copy_password_d.gif")); ; copyPasswordButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { copyPasswordToClipboard(); } }); copyPasswordButton.setEnabled(false); toolbar.add(copyPasswordButton); // The "Launch URL" button launchURLButton = new JButton(); launchURLButton.setToolTipText(Translator.translate(LAUNCH_URL_TXT)); launchURLButton.setIcon(Util.loadImage("launch_URL.gif")); launchURLButton.setDisabledIcon(Util.loadImage("launch_URL_d.gif")); ; launchURLButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { AccountInformation accInfo = dbActions.getSelectedAccount(); String uRl = accInfo.getUrl(); // Check if the selected url is null or emty and inform the user // via JoptioPane message if ((uRl == null) || (uRl.length() == 0)) { JOptionPane.showMessageDialog(launchURLButton.getParent(), Translator.translate("EmptyUrlJoptionpaneMsg"), Translator.translate("UrlErrorJoptionpaneTitle"), JOptionPane.WARNING_MESSAGE); // Check if the selected url is a valid formated url(via // urlIsValid() method) and inform the user via JoptioPane // message } else if (!(urlIsValid(uRl))) { JOptionPane.showMessageDialog(launchURLButton.getParent(), Translator.translate("InvalidUrlJoptionpaneMsg"), Translator.translate("UrlErrorJoptionpaneTitle"), JOptionPane.WARNING_MESSAGE); // Call the method LaunchSelectedURL() using the selected // url as input } else { LaunchSelectedURL(uRl); } } }); launchURLButton.setEnabled(false); toolbar.add(launchURLButton); toolbar.addSeparator(); // The "Option" button optionsButton = new JButton(); optionsButton.setToolTipText(Translator.translate(OPTIONS_TXT)); optionsButton.setIcon(Util.loadImage("options.gif")); optionsButton.setDisabledIcon(Util.loadImage("options_d.gif")); ; optionsButton.addActionListener(this); optionsButton.setEnabled(true); optionsButton.setActionCommand(OPTIONS_TXT); toolbar.add(optionsButton); toolbar.addSeparator(); // The Sync database button syncDatabaseButton = new JButton(); syncDatabaseButton.setToolTipText(Translator.translate(SYNC_DATABASE_TXT)); syncDatabaseButton.setIcon(Util.loadImage("sync.png")); syncDatabaseButton.setDisabledIcon(Util.loadImage("sync_d.png")); ; syncDatabaseButton.addActionListener(this); syncDatabaseButton.setEnabled(false); syncDatabaseButton.setActionCommand(SYNC_DATABASE_TXT); toolbar.add(syncDatabaseButton); return toolbar; } private JMenuBar createMenuBar() { JMenuBar menuBar = new JMenuBar(); databaseMenu = new JMenu(Translator.translate("databaseMenu")); databaseMenu.setMnemonic(KeyEvent.VK_D); menuBar.add(databaseMenu); newDatabaseMenuItem = new JMenuItem(Translator.translate(NEW_DATABASE_TXT), KeyEvent.VK_N); newDatabaseMenuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_N, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); databaseMenu.add(newDatabaseMenuItem); newDatabaseMenuItem.addActionListener(this); newDatabaseMenuItem.setActionCommand(NEW_DATABASE_TXT); openDatabaseMenuItem = new JMenuItem(Translator.translate(OPEN_DATABASE_TXT), KeyEvent.VK_O); openDatabaseMenuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_O, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); databaseMenu.add(openDatabaseMenuItem); openDatabaseMenuItem.addActionListener(this); openDatabaseMenuItem.setActionCommand(OPEN_DATABASE_TXT); openDatabaseFromURLMenuItem = new JMenuItem(Translator.translate(OPEN_DATABASE_FROM_URL_TXT), KeyEvent.VK_L); openDatabaseFromURLMenuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_L, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); databaseMenu.add(openDatabaseFromURLMenuItem); openDatabaseFromURLMenuItem.addActionListener(this); openDatabaseFromURLMenuItem.setActionCommand(OPEN_DATABASE_FROM_URL_TXT); databaseMenu.addSeparator(); syncWithRemoteDatabaseMenuItem = new JMenuItem(Translator.translate(SYNC_DATABASE_TXT), KeyEvent.VK_S); syncWithRemoteDatabaseMenuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_S, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); databaseMenu.add(syncWithRemoteDatabaseMenuItem); syncWithRemoteDatabaseMenuItem.addActionListener(this); syncWithRemoteDatabaseMenuItem.setEnabled(false); syncWithRemoteDatabaseMenuItem.setActionCommand(SYNC_DATABASE_TXT); changeMasterPasswordMenuItem = new JMenuItem(Translator.translate(CHANGE_MASTER_PASSWORD_TXT), KeyEvent.VK_G); changeMasterPasswordMenuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_G, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); databaseMenu.add(changeMasterPasswordMenuItem); changeMasterPasswordMenuItem.addActionListener(this); changeMasterPasswordMenuItem.setEnabled(false); changeMasterPasswordMenuItem.setActionCommand(CHANGE_MASTER_PASSWORD_TXT); databasePropertiesMenuItem = new JMenuItem(Translator.translate(DATABASE_PROPERTIES_TXT), KeyEvent.VK_I); databasePropertiesMenuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_I, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); databaseMenu.add(databasePropertiesMenuItem); databasePropertiesMenuItem.addActionListener(this); databasePropertiesMenuItem.setEnabled(false); databasePropertiesMenuItem.setActionCommand(DATABASE_PROPERTIES_TXT); databaseMenu.addSeparator(); exportMenuItem = new JMenuItem(Translator.translate(EXPORT_TXT)); databaseMenu.add(exportMenuItem); exportMenuItem.addActionListener(this); exportMenuItem.setEnabled(false); exportMenuItem.setActionCommand(EXPORT_TXT); importMenuItem = new JMenuItem(Translator.translate(IMPORT_TXT)); databaseMenu.add(importMenuItem); importMenuItem.addActionListener(this); importMenuItem.setEnabled(false); importMenuItem.setActionCommand(IMPORT_TXT); accountMenu = new JMenu(Translator.translate("accountMenu")); accountMenu.setMnemonic(KeyEvent.VK_A); menuBar.add(accountMenu); addAccountMenuItem = new JMenuItem(Translator.translate(ADD_ACCOUNT_TXT), KeyEvent.VK_A); addAccountMenuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_A, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); accountMenu.add(addAccountMenuItem); addAccountMenuItem.addActionListener(this); addAccountMenuItem.setEnabled(false); addAccountMenuItem.setActionCommand(ADD_ACCOUNT_TXT); editAccountMenuItem = new JMenuItem(Translator.translate(EDIT_ACCOUNT_TXT), KeyEvent.VK_E); editAccountMenuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_E, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); accountMenu.add(editAccountMenuItem); editAccountMenuItem.addActionListener(this); editAccountMenuItem.setEnabled(false); editAccountMenuItem.setActionCommand(EDIT_ACCOUNT_TXT); deleteAccountMenuItem = new JMenuItem(Translator.translate(DELETE_ACCOUNT_TXT), KeyEvent.VK_D); deleteAccountMenuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_D, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); accountMenu.add(deleteAccountMenuItem); deleteAccountMenuItem.addActionListener(this); deleteAccountMenuItem.setEnabled(false); deleteAccountMenuItem.setActionCommand(DELETE_ACCOUNT_TXT); viewAccountMenuItem = new JMenuItem(Translator.translate(VIEW_ACCOUNT_TXT), KeyEvent.VK_V); viewAccountMenuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_V, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); accountMenu.add(viewAccountMenuItem); viewAccountMenuItem.addActionListener(this); viewAccountMenuItem.setEnabled(false); viewAccountMenuItem.setActionCommand(VIEW_ACCOUNT_TXT); copyUsernameMenuItem = new JMenuItem(Translator.translate(COPY_USERNAME_TXT), KeyEvent.VK_U); copyUsernameMenuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_U, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); accountMenu.add(copyUsernameMenuItem); copyUsernameMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { copyUsernameToClipboard(); } }); copyUsernameMenuItem.setEnabled(false); copyUsernameMenuItem.setActionCommand(COPY_USERNAME_TXT); copyPasswordMenuItem = new JMenuItem(Translator.translate(COPY_PASSWORD_TXT), KeyEvent.VK_P); copyPasswordMenuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_P, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); accountMenu.add(copyPasswordMenuItem); copyPasswordMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { copyPasswordToClipboard(); } }); copyPasswordMenuItem.setEnabled(false); copyPasswordMenuItem.setActionCommand(COPY_PASSWORD_TXT); launchURLMenuItem = new JMenuItem(Translator.translate(LAUNCH_URL_TXT), KeyEvent.VK_B); launchURLMenuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_B, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); accountMenu.add(launchURLMenuItem); launchURLMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { AccountInformation accInfo = dbActions.getSelectedAccount(); String uRl = accInfo.getUrl(); // Check if the selected url is null or emty and inform the user // via JoptioPane message if ((uRl == null) || (uRl.length() == 0)) { JOptionPane.showMessageDialog(accountMenu.getParent().getParent(), Translator.translate("EmptyUrlJoptionpaneMsg"), Translator.translate("UrlErrorJoptionpaneTitle"), JOptionPane.WARNING_MESSAGE); // Check if the selected url is a valid formated url(via // urlIsValid() method) and inform the user via JoptioPane // message } else if (!(urlIsValid(uRl))) { JOptionPane.showMessageDialog(accountMenu.getParent().getParent(), Translator.translate("InvalidUrlJoptionpaneMsg"), Translator.translate("UrlErrorJoptionpaneTitle"), JOptionPane.WARNING_MESSAGE); // Call the method LaunchSelectedURL() using the selected // url as input } else { LaunchSelectedURL(uRl); } } }); launchURLMenuItem.setEnabled(false); launchURLMenuItem.setActionCommand(LAUNCH_URL_TXT); exitMenuItem = new JMenuItem(Translator.translate(EXIT_TXT), KeyEvent.VK_X); exitMenuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_X, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); exitMenuItem.addActionListener(this); exitMenuItem.setActionCommand(EXIT_TXT); aboutMenuItem = new JMenuItem(Translator.translate(ABOUT_TXT), KeyEvent.VK_A); aboutMenuItem.addActionListener(this); aboutMenuItem.setActionCommand(ABOUT_TXT); // Because the MAC version of UPM will have a program item in the menu // bar then these items // only need to be added on non-mac platforms if (!PlatformSpecificCode.isMAC()) { databaseMenu.addSeparator(); databaseMenu.add(exitMenuItem); helpMenu = new JMenu(Translator.translate("helpMenu")); helpMenu.setMnemonic(KeyEvent.VK_H); menuBar.add(helpMenu); helpMenu.add(aboutMenuItem); } return menuBar; } public JList getAccountsListview() { return accountsListview; } private void copyUsernameToClipboard() { AccountInformation accInfo = dbActions.getSelectedAccount(); copyToClipboard(new String(accInfo.getUserId())); } private void copyPasswordToClipboard() { AccountInformation accInfo = dbActions.getSelectedAccount(); copyToClipboard(new String(accInfo.getPassword())); } private void copyToClipboard(String s) { StringSelection stringSelection = new StringSelection(s); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents(stringSelection, stringSelection); } // Use com.apache.commons.validator library in order to check the // validity(proper formating, e.x http://www.url.com) of the given url private boolean urlIsValid(String urL) { UrlValidator urlValidator = new UrlValidator(); if (urlValidator.isValid(urL)) { return true; } else { return false; } } // Method that get(as input) the selected Account URL and open this URL via // the default browser of our platform private void LaunchSelectedURL(String url) { if (Desktop.isDesktopSupported()) { Desktop desktop = Desktop.getDesktop(); try { desktop.browse(new URI(url)); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (URISyntaxException e) { // TODO Auto-generated catch block e.printStackTrace(); } // Linux and Mac specific code in order to launch url } else { Runtime runtime = Runtime.getRuntime(); try { runtime.exec("xdg-open " + url); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * Writes current window position and size to the preferences */ private void storeWindowBounds() { Preferences.set(Preferences.ApplicationOptions.XLOC, Integer.toString(this.getX())); Preferences.set(Preferences.ApplicationOptions.YLOC, Integer.toString(this.getY())); Preferences.set(Preferences.ApplicationOptions.WWIDTH, Integer.toString(this.getWidth())); Preferences.set(Preferences.ApplicationOptions.WHEIGHT, Integer.toString(this.getHeight())); } /** * Restores the window position and size to those found in the preferences * Checks if the window can still be displayed, if not, revert to default * position */ private void restoreWindowBounds() { int x = Preferences.getInt(Preferences.ApplicationOptions.XLOC, this.getX()); int y = Preferences.getInt(Preferences.ApplicationOptions.YLOC, this.getY()); // check if this position can still be displayed to avoid problems // for people who dragged the window on a screen that is no longer // connected. if (getGraphicsConfigurationContaining(x, y) == null) { x = this.getX(); y = this.getY(); } int width = Preferences.getInt(Preferences.ApplicationOptions.WWIDTH, (this.getWidth())); int height = Preferences.getInt(Preferences.ApplicationOptions.WHEIGHT, this.getHeight()); this.setBounds(x, y, width, height); } /** * Utility function for restoreWindowBounds */ private GraphicsConfiguration getGraphicsConfigurationContaining(int x, int y) { ArrayList configs = new ArrayList(); GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice[] devices = env.getScreenDevices(); for (int i = 0; i < devices.length; i++) { GraphicsConfiguration[] gconfigs = devices[i].getConfigurations(); configs.addAll(Arrays.asList(gconfigs)); } for (int i = 0; i < configs.size(); i++) { GraphicsConfiguration config = ((GraphicsConfiguration) configs.get(i)); Rectangle bounds = config.getBounds(); if (bounds.contains(x, y)) { return config; } } return null; } /** * Convenience method to iterate over all graphics configurations. */ private static ArrayList getConfigs() { ArrayList result = new ArrayList(); GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice[] devices = env.getScreenDevices(); for (int i = 0; i < devices.length; i++) { GraphicsConfiguration[] configs = devices[i].getConfigurations(); result.addAll(Arrays.asList(configs)); } return result; } public JButton getCopyPasswordButton() { return copyPasswordButton; } public JButton getLaunchURLButton() { return launchURLButton; } public JButton getCopyUsernameButton() { return copyUsernameButton; } public JButton getEditAccountButton() { return editAccountButton; } public JButton getAddAccountButton() { return addAccountButton; } public JButton getOptionsButton() { return optionsButton; } public JButton getDeleteAccountButton() { return deleteAccountButton; } public JTextField getSearchField() { return searchField; } public JLabel getSearchIcon() { return searchIcon; } public JButton getResetSearchButton() { return resetSearchButton; } public JMenuItem getAboutMenuItem() { return aboutMenuItem; } public JMenuItem getExitMenuItem() { return exitMenuItem; } public JMenuItem getCopyPasswordMenuItem() { return copyPasswordMenuItem; } public JMenuItem getLaunchURLMenuItem() { return launchURLMenuItem; } public JMenuItem getCopyUsernameMenuItem() { return copyUsernameMenuItem; } public JMenuItem getDeleteAccountMenuItem() { return deleteAccountMenuItem; } public JMenuItem getViewAccountMenuItem() { return viewAccountMenuItem; } public JMenuItem getEditAccountMenuItem() { return editAccountMenuItem; } public static String getApplicationName() { return applicationName; } public JMenuItem getAddAccountMenuItem() { return addAccountMenuItem; } public JMenuItem getChangeMasterPasswordMenuItem() { return changeMasterPasswordMenuItem; } public JMenuItem getDatabasePropertiesMenuItem() { return databasePropertiesMenuItem; } public void actionPerformed(ActionEvent event) { try { if (event.getActionCommand() == MainWindow.NEW_DATABASE_TXT) { dbActions.newDatabase(); } else if (event.getActionCommand() == MainWindow.OPEN_DATABASE_TXT) { dbActions.openDatabase(); } else if (event.getActionCommand() == MainWindow.OPEN_DATABASE_FROM_URL_TXT) { dbActions.openDatabaseFromURL(); } else if (event.getActionCommand() == MainWindow.SYNC_DATABASE_TXT) { dbActions.syncWithRemoteDatabase(); } else if (event.getActionCommand() == MainWindow.ADD_ACCOUNT_TXT) { dbActions.reloadDatabaseBefore(new AddAccountAction()); } else if (event.getActionCommand() == MainWindow.EDIT_ACCOUNT_TXT) { String selectedAccName = (String) this.accountsListview.getSelectedValue(); dbActions.reloadDatabaseBefore(new EditAccountAction(selectedAccName)); } else if (event.getActionCommand() == MainWindow.DELETE_ACCOUNT_TXT) { dbActions.reloadDatabaseBefore(new DeleteAccountAction()); } else if (event.getActionCommand() == MainWindow.VIEW_ACCOUNT_TXT) { dbActions.viewAccount(); } else if (event.getActionCommand() == MainWindow.OPTIONS_TXT) { dbActions.options(); } else if (event.getActionCommand() == MainWindow.ABOUT_TXT) { dbActions.showAbout(); } else if (event.getActionCommand() == MainWindow.RESET_SEARCH_TXT) { dbActions.resetSearch(); } else if (event.getActionCommand() == MainWindow.CHANGE_MASTER_PASSWORD_TXT) { dbActions.reloadDatabaseBefore(new ChangeMasterPasswordAction()); } else if (event.getActionCommand() == MainWindow.DATABASE_PROPERTIES_TXT) { dbActions.reloadDatabaseBefore(new ShowDatabasePropertiesAction()); } else if (event.getActionCommand() == MainWindow.EXIT_TXT) { dbActions.exitApplication(); } else if (event.getActionCommand() == MainWindow.EXPORT_TXT) { dbActions.export(); } else if (event.getActionCommand() == MainWindow.IMPORT_TXT) { dbActions.reloadDatabaseBefore(new ImportAccountsAction()); } } catch (Exception e) { dbActions.errorHandler(e); } } public JButton getSyncWithRemoteDatabaseButton() { return syncDatabaseButton; } public JMenuItem getSyncWithRemoteDatabaseMenuItem() { return syncWithRemoteDatabaseMenuItem; } public JMenuItem getExportMenuItem() { return exportMenuItem; } public JMenuItem getImportMenuItem() { return importMenuItem; } public JLabel getStatusBar() { return statusBar; } public JPanel getDatabaseFileChangedPanel() { return databaseFileChangedPanel; } /** * Initialise all the menus, buttons, etc to take account of the language * selected by the user */ public void initialiseControlsWithDefaultLanguage() { databaseMenu.setText(Translator.translate("databaseMenu")); newDatabaseMenuItem.setText(Translator.translate(NEW_DATABASE_TXT)); openDatabaseMenuItem.setText(Translator.translate(OPEN_DATABASE_TXT)); openDatabaseFromURLMenuItem.setText(Translator.translate(OPEN_DATABASE_FROM_URL_TXT)); syncWithRemoteDatabaseMenuItem.setText(Translator.translate(SYNC_DATABASE_TXT)); changeMasterPasswordMenuItem.setText(Translator.translate(CHANGE_MASTER_PASSWORD_TXT)); databasePropertiesMenuItem.setText(Translator.translate(DATABASE_PROPERTIES_TXT)); accountMenu.setText(Translator.translate("accountMenu")); addAccountMenuItem.setText(Translator.translate(ADD_ACCOUNT_TXT)); editAccountMenuItem.setText(Translator.translate(EDIT_ACCOUNT_TXT)); deleteAccountMenuItem.setText(Translator.translate(DELETE_ACCOUNT_TXT)); viewAccountMenuItem.setText(Translator.translate(VIEW_ACCOUNT_TXT)); copyUsernameMenuItem.setText(Translator.translate(COPY_USERNAME_TXT)); copyPasswordMenuItem.setText(Translator.translate(COPY_PASSWORD_TXT)); launchURLMenuItem.setText(Translator.translate(LAUNCH_URL_TXT)); exitMenuItem.setText(Translator.translate(EXIT_TXT)); aboutMenuItem.setText(Translator.translate(ABOUT_TXT)); exportMenuItem.setText(Translator.translate(EXPORT_TXT)); importMenuItem.setText(Translator.translate(IMPORT_TXT)); // Because the MAC version of UPM will have a program item in the menu // bar then these items // only need to be added on non-mac platforms if (!PlatformSpecificCode.isMAC()) { helpMenu.setText(Translator.translate("helpMenu")); } addAccountButton.setToolTipText(Translator.translate(ADD_ACCOUNT_TXT)); editAccountButton.setToolTipText(Translator.translate(EDIT_ACCOUNT_TXT)); deleteAccountButton.setToolTipText(Translator.translate(DELETE_ACCOUNT_TXT)); copyUsernameButton.setToolTipText(Translator.translate(COPY_USERNAME_TXT)); copyPasswordButton.setToolTipText(Translator.translate(COPY_PASSWORD_TXT)); launchURLButton.setToolTipText(Translator.translate(LAUNCH_URL_TXT)); optionsButton.setToolTipText(Translator.translate(OPTIONS_TXT)); syncDatabaseButton.setToolTipText(Translator.translate(SYNC_DATABASE_TXT)); resetSearchButton.setToolTipText(Translator.translate(RESET_SEARCH_TXT)); } public interface ChangeDatabaseAction { public void doAction(); } private class EditAccountAction implements ChangeDatabaseAction { private String accountToEdit; public EditAccountAction(String accountToEdit) { this.accountToEdit = accountToEdit; } public void doAction() { try { dbActions.editAccount(accountToEdit); } catch (Exception e) { dbActions.errorHandler(e); } } } private class ChangeMasterPasswordAction implements ChangeDatabaseAction { public void doAction() { try { dbActions.changeMasterPassword(); } catch (Exception e) { dbActions.errorHandler(e); } } } private class DeleteAccountAction implements ChangeDatabaseAction { public void doAction() { try { dbActions.deleteAccount(); } catch (Exception e) { dbActions.errorHandler(e); } } } private class AddAccountAction implements ChangeDatabaseAction { public void doAction() { try { dbActions.addAccount(); } catch (Exception e) { dbActions.errorHandler(e); } } } private class ShowDatabasePropertiesAction implements ChangeDatabaseAction { public void doAction() { try { dbActions.showDatabaseProperties(); } catch (Exception e) { dbActions.errorHandler(e); } } } private class ImportAccountsAction implements ChangeDatabaseAction { public void doAction() { try { dbActions.importAccounts(); } catch (Exception e) { dbActions.errorHandler(e); } } } }