/*
* 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);
}
}
}
}