content: /*
   * 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.Container;
  import java.awt.Desktop;
  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.DataFlavor;
  import java.awt.datatransfer.StringSelection;
  import java.awt.datatransfer.Transferable;
  import java.awt.datatransfer.UnsupportedFlavorException;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.awt.event.FocusAdapter;
  import java.awt.event.FocusEvent;
  import java.awt.event.ItemEvent;
  import java.awt.event.ItemListener;
  import java.awt.event.MouseAdapter;
  import java.awt.event.MouseEvent;
  import java.io.IOException;
  import java.net.URI;
  import java.net.URISyntaxException;
  import java.security.SecureRandom;
  import java.util.ArrayList;
  
  import javax.swing.JButton;
  import javax.swing.JCheckBox;
  import javax.swing.JFrame;
  import javax.swing.JLabel;
  import javax.swing.JOptionPane;
  import javax.swing.JPanel;
  import javax.swing.JPasswordField;
  import javax.swing.JScrollPane;
  import javax.swing.JSeparator;
  import javax.swing.JTextArea;
  import javax.swing.JTextField;
  
  import org.apache.commons.validator.routines.UrlValidator;
  
  import com._17od.upm.database.AccountInformation;
  import com._17od.upm.util.Preferences;
  import com._17od.upm.util.Translator;
  import com._17od.upm.util.Util;
  
  public class AccountDialog extends EscapeDialog {
  
  	private static final long serialVersionUID = 1L;
  	private static final char[] ALLOWED_CHARS = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
  			'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
  			'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3',
  			'4', '5', '6', '7', '8', '9' };
  	// Extended CharArray list which include also 24 Escape characters for
  	// stronger password generation
  	private static final char[] EXTRA_ALLOWED_CHARS = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
  			'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
  			'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2',
  			'3', '4', '5', '6', '7', '8', '9', '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ',', ')', '_', '-',
  			'+', '=', '|', '/', '<', '>', '.', '?', ';', ':' };
  
  	/*
  	 * We will use the (4)four above CharArray lists(UPPERCASE_CHARS,
  	 * LOWERCASE_CHARS, NUMBER_CHARS, ESCAPE_CHARS) to ensure that the generated
  	 * passwords will be more complex. If the user has selected to include
  	 * escape characters to generated passwords and the length of the passwords
  	 * is 4 or above, then we will use some methods in order to generate
  	 * passwords that will have at least 1 lower case + 1 upper case + 1 number
  	 * + 1 escape character. On the other hand, if the user has not selected to
  	 * include escape characters to generated passwords and the length of the
  	 * passwords is at least 3, then we will use methods in order to generate
  	 * passwords that will have at least 1 lower case + 1 upper case + 1 number.
  	 */
  	private static final char[] UPPERCASE_CHARS = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
  			'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
  
  	};
  
  	private static final char[] LOWERCASE_CHARS = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
  			'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
  
  	};
  
  	private static final char[] NUMBER_CHARS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
  
  	private static final char[] PUNCTUATION_CHARS = { '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ',', ')', '_',
  			'-', '+', '=', '|', '/', '<', '>', '.', '?', ';', ':' };
  
  	private AccountInformation pAccount;
  	private JTextField userId;
  	private JPasswordField password;
  	private JTextArea notes;
  	private JTextField url;
  	private JTextField accountName;
  	private boolean okClicked = false;
  	private ArrayList existingAccounts;
  	private JFrame parentWindow;
  	private boolean accountChanged = false;
  	private char defaultEchoChar;
  
  	public AccountDialog(AccountInformation account, JFrame parentWindow, boolean readOnly,
  			ArrayList existingAccounts) {
  		super(parentWindow, true);
  
  		boolean addingAccount = false;
  		
  		//Request focus on Account JDialog when mouse clicked
  		this.addMouseListener(new MouseAdapter() {
  			public void mouseClicked(MouseEvent e) {
  				if (e.getClickCount() == 1) {
  					requestFocus();
  					
  				}
  			}});
  
  		// Set the title based on weather we've been opened in readonly mode and
  		// weather the
  		// Account passed in is empty or not
  		String title = null;
  		if (readOnly) {
  			title = Translator.translate("viewAccount");
  		} else if (!readOnly && account.getAccountName().trim().equals("")) {
  			title = Translator.translate("addAccount");
  			addingAccount = true;
  		} else {
  			title = Translator.translate("editAccount");
  		}
  		setTitle(title);
  
  		this.pAccount = account;
  		this.existingAccounts = existingAccounts;
  		this.parentWindow = parentWindow;
  
  		getContentPane().setLayout(new GridBagLayout());
  		GridBagConstraints c = new GridBagConstraints();
  
  		Container container = getContentPane();
  
  		// The AccountName Row
  		JLabel accountLabel = new JLabel(Translator.translate("account"));
  		c.gridx = 0;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(10, 10, 10, 10);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.NONE;
  		container.add(accountLabel, c);
  
  		// This panel will hold the Account field and the copy and paste
  		// buttons.
  		JPanel accountPanel = new JPanel(new GridBagLayout());
  
  		accountName = new JTextField(new String(pAccount.getAccountName()), 20);
  		if (readOnly) {
  			accountName.setEditable(false);
  		}
  		c.gridx = 0;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(0, 0, 0, 5);
  		c.weightx = 1;
  		c.weighty = 1;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.HORIZONTAL;
  		accountPanel.add(accountName, c);
  		accountName.addFocusListener(new FocusAdapter() {
  			public void focusGained(FocusEvent e) {
  				accountName.selectAll();
  			}
  		});
  
  		JButton acctCopyButton = new JButton();
  		acctCopyButton.setIcon(Util.loadImage("copy-icon.png"));
  		acctCopyButton.setToolTipText("Copy");
  		acctCopyButton.setEnabled(true);
  		acctCopyButton.setMargin(new Insets(0, 0, 0, 0));
  		acctCopyButton.addActionListener(new ActionListener() {
  			public void actionPerformed(ActionEvent ae) {
  				copyTextField(accountName);
  			}
  		});
  		c.gridx = 1;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(0, 0, 0, 5);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.NONE;
  		accountPanel.add(acctCopyButton, c);
  
  		JButton acctPasteButton = new JButton();
  		acctPasteButton.setIcon(Util.loadImage("paste-icon.png"));
  		acctPasteButton.setToolTipText("Paste");
  		acctPasteButton.setEnabled(!readOnly);
  		acctPasteButton.setMargin(new Insets(0, 0, 0, 0));
  		acctPasteButton.addActionListener(new ActionListener() {
  			public void actionPerformed(ActionEvent ae) {
  				pasteToTextField(accountName);
  			}
  		});
  		c.gridx = 2;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(0, 0, 0, 5);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.NONE;
  		accountPanel.add(acctPasteButton, c);
  
  		c.gridx = 1;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(10, 10, 10, 10);
  		c.weightx = 1;
  		c.weighty = 1;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.HORIZONTAL;
  		container.add(accountPanel, c);
  
  		// Userid Row
  		JLabel useridLabel = new JLabel(Translator.translate("userid"));
  		c.gridx = 0;
  		c.gridy = 1;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(10, 10, 10, 10);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.NONE;
  		container.add(useridLabel, c);
  
  		// This panel will hold the User ID field and the copy and paste
  		// buttons.
  		JPanel idPanel = new JPanel(new GridBagLayout());
  
  		userId = new JTextField(new String(pAccount.getUserId()), 20);
  		if (readOnly) {
  			userId.setEditable(false);
  		}
  		c.gridx = 0;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(0, 0, 0, 5);
  		c.weightx = 1;
  		c.weighty = 1;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.HORIZONTAL;
  		idPanel.add(userId, c);
  		userId.addFocusListener(new FocusAdapter() {
  			public void focusGained(FocusEvent e) {
  				userId.selectAll();
  			}
  		});
  
  		JButton idCopyButton = new JButton();
  		idCopyButton.setIcon(Util.loadImage("copy-icon.png"));
  		idCopyButton.setToolTipText("Copy");
  		idCopyButton.setEnabled(true);
  		idCopyButton.setMargin(new Insets(0, 0, 0, 0));
  		idCopyButton.addActionListener(new ActionListener() {
  			public void actionPerformed(ActionEvent ae) {
  				copyTextField(userId);
  			}
  		});
  		c.gridx = 1;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(0, 0, 0, 5);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.NONE;
  		idPanel.add(idCopyButton, c);
  
  		JButton idPasteButton = new JButton();
  		idPasteButton.setIcon(Util.loadImage("paste-icon.png"));
  		idPasteButton.setToolTipText("Paste");
  		idPasteButton.setEnabled(!readOnly);
  		idPasteButton.setMargin(new Insets(0, 0, 0, 0));
  		idPasteButton.addActionListener(new ActionListener() {
  			public void actionPerformed(ActionEvent ae) {
  				pasteToTextField(userId);
  			}
  		});
  		c.gridx = 2;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(0, 0, 0, 5);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.NONE;
  		idPanel.add(idPasteButton, c);
  
  		c.gridx = 1;
  		c.gridy = 1;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(10, 10, 10, 10);
  		c.weightx = 1;
  		c.weighty = 1;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.HORIZONTAL;
  		container.add(idPanel, c);
  
  		// Password Row
  		JLabel passwordLabel = new JLabel(Translator.translate("password"));
  		c.gridx = 0;
  		c.gridy = 2;
  		c.anchor = GridBagConstraints.FIRST_LINE_START;
  		c.insets = new Insets(15, 10, 10, 10);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.NONE;
  		container.add(passwordLabel, c);
  
  		// This panel will hold the password, generate password button, copy and
  		// paste buttons, and hide password checkbox
  		JPanel passwordPanel = new JPanel(new GridBagLayout());
  
  		password = new JPasswordField(new String(pAccount.getPassword()), 20);
  		// allow CTRL-C on the password field
  		password.putClientProperty("JPasswordField.cutCopyAllowed", Boolean.TRUE);
  		password.setEditable(!readOnly);
  		password.addFocusListener(new FocusAdapter() {
  			public void focusGained(FocusEvent e) {
  				password.selectAll();
  			}
  		});
  		c.gridx = 0;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(0, 0, 0, 5);
  		c.weightx = 1;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.HORIZONTAL;
  		passwordPanel.add(password, c);
  
  		JButton generateRandomPasswordButton = new JButton(Translator.translate("generate"));
  		if (readOnly) {
  			generateRandomPasswordButton.setEnabled(false);
  		}
  		generateRandomPasswordButton.addActionListener(new ActionListener() {
  			public void actionPerformed(ActionEvent actionevent) {
  				// Get the user's preference about including or not Escape
  				// Characters to generated passwords
  				Boolean includeEscapeChars = new Boolean(
  						Preferences.get(Preferences.ApplicationOptions.INCLUDE_ESCAPE_CHARACTERS, "true"));
  				int pwLength = Preferences.getInt(Preferences.ApplicationOptions.ACCOUNT_PASSWORD_LENGTH, 8);
  				String Password;
  
  				if ((includeEscapeChars.booleanValue()) && (pwLength > 3)) {
  					// Verify that the generated password satisfies the criteria
  					// for strong passwords(including Escape Characters)
  					do {
  						Password = GeneratePassword(pwLength, includeEscapeChars.booleanValue());
  					} while (!(CheckPassStrong(Password, includeEscapeChars.booleanValue())));
  
  				} else if (!(includeEscapeChars.booleanValue()) && (pwLength > 2)) {
  					// Verify that the generated password satisfies the criteria
  					// for strong passwords(excluding Escape Characters)
  					do {
  						Password = GeneratePassword(pwLength, includeEscapeChars.booleanValue());
  					} while (!(CheckPassStrong(Password, includeEscapeChars.booleanValue())));
  
  				} else {
  					// Else a weak password of 3 or less chars will be produced
  					Password = GeneratePassword(pwLength, includeEscapeChars.booleanValue());
  				}
  				password.setText(Password);
  			}
  		});
  		if (addingAccount) {
  			generateRandomPasswordButton.doClick();
  		}
  		c.gridx = 1;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(0, 0, 0, 5);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.HORIZONTAL;
  		passwordPanel.add(generateRandomPasswordButton, c);
  
  		JButton pwCopyButton = new JButton();
  		pwCopyButton.setIcon(Util.loadImage("copy-icon.png"));
  		pwCopyButton.setToolTipText("Copy");
  		pwCopyButton.setEnabled(true);
  		pwCopyButton.setMargin(new Insets(0, 0, 0, 0));
  		pwCopyButton.addActionListener(new ActionListener() {
  			public void actionPerformed(ActionEvent ae) {
  				copyTextField(password);
  			}
  		});
  		c.gridx = 2;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(0, 0, 0, 5);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.HORIZONTAL;
  		passwordPanel.add(pwCopyButton, c);
  
  		JButton pwPasteButton = new JButton();
  		pwPasteButton.setIcon(Util.loadImage("paste-icon.png"));
  		pwPasteButton.setToolTipText("Paste");
  		pwPasteButton.setEnabled(!readOnly);
  		pwPasteButton.setMargin(new Insets(0, 0, 0, 0));
  		pwPasteButton.addActionListener(new ActionListener() {
  			public void actionPerformed(ActionEvent ae) {
  				pasteToTextField(password);
  			}
  		});
  		c.gridx = 3;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(0, 0, 0, 5);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.HORIZONTAL;
  		passwordPanel.add(pwPasteButton, c);
  
  		JCheckBox hidePasswordCheckbox = new JCheckBox(Translator.translate("hide"), true);
  		defaultEchoChar = password.getEchoChar();
  		hidePasswordCheckbox.setMargin(new Insets(5, 0, 5, 0));
  		hidePasswordCheckbox.addItemListener(new ItemListener() {
  			public void itemStateChanged(ItemEvent e) {
  				if (e.getStateChange() == ItemEvent.SELECTED) {
  					password.setEchoChar(defaultEchoChar);
  				} else {
  					password.setEchoChar((char) 0);
  				}
  			}
  		});
  
  		Boolean hideAccountPassword = new Boolean(
  				Preferences.get(Preferences.ApplicationOptions.ACCOUNT_HIDE_PASSWORD, "true"));
  		hidePasswordCheckbox.setSelected(hideAccountPassword.booleanValue());
  
  		c.gridx = 0;
  		c.gridy = 1;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(0, 0, 0, 0);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.HORIZONTAL;
  		passwordPanel.add(hidePasswordCheckbox, c);
  
  		c.gridx = 1;
  		c.gridy = 2;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(10, 10, 10, 10);
  		c.weightx = 1;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.HORIZONTAL;
  		container.add(passwordPanel, c);
  
  		// URL Row
  		JLabel urlLabel = new JLabel(Translator.translate("url"));
  		c.gridx = 0;
  		c.gridy = 3;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(10, 10, 10, 10);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.NONE;
  		container.add(urlLabel, c);
  
  		// This panel will hold the URL field and the copy and paste buttons.
  		JPanel urlPanel = new JPanel(new GridBagLayout());
  
  		url = new JTextField(new String(pAccount.getUrl()), 20);
  		if (readOnly) {
  			url.setEditable(false);
  		}
  		c.gridx = 0;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(0, 0, 0, 5);
  		c.weightx = 1;
  		c.weighty = 1;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.HORIZONTAL;
  		urlPanel.add(url, c);
  		url.addFocusListener(new FocusAdapter() {
  			public void focusGained(FocusEvent e) {
  				url.selectAll();
  			}
  		});
  
  		final JButton urlLaunchButton = new JButton();
  		urlLaunchButton.setIcon(Util.loadImage("launch-url-sm.png"));
  		urlLaunchButton.setToolTipText("Launch URL");
  		urlLaunchButton.setEnabled(true);
  		urlLaunchButton.setMargin(new Insets(0, 0, 0, 0));
  		urlLaunchButton.addActionListener(new ActionListener() {
  			public void actionPerformed(ActionEvent ae) {
  				String urlText = url.getText();
  
  				// Check if the selected url is null or emty and inform the user
  				// via JoptioPane message
  				if ((urlText == null) || (urlText.length() == 0)) {
  					JOptionPane.showMessageDialog(urlLaunchButton.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(urlText))) {
  					JOptionPane.showMessageDialog(urlLaunchButton.getParent(),
  							Translator.translate("InvalidUrlJoptionpaneMsg"),
  							Translator.translate("UrlErrorJoptionpaneTitle"), JOptionPane.WARNING_MESSAGE);
  					// Call the method LaunchSelectedURL() using the selected
  					// url as input
  				} else {
  					LaunchSelectedURL(urlText);
  				}
  			}
  		});
  		c.gridx = 1;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(0, 0, 0, 5);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.NONE;
  		urlPanel.add(urlLaunchButton, c);
  
  		JButton urlCopyButton = new JButton();
  		urlCopyButton.setIcon(Util.loadImage("copy-icon.png"));
  		urlCopyButton.setToolTipText("Copy");
  		urlCopyButton.setEnabled(true);
  		urlCopyButton.setMargin(new Insets(0, 0, 0, 0));
  		urlCopyButton.addActionListener(new ActionListener() {
  			public void actionPerformed(ActionEvent ae) {
  				copyTextField(url);
  			}
  		});
  		c.gridx = 2;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(0, 0, 0, 5);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.NONE;
  		urlPanel.add(urlCopyButton, c);
  
  		JButton urlPasteButton = new JButton();
  		urlPasteButton.setIcon(Util.loadImage("paste-icon.png"));
  		urlPasteButton.setToolTipText("Paste");
  		urlPasteButton.setEnabled(!readOnly);
  		urlPasteButton.setMargin(new Insets(0, 0, 0, 0));
  		urlPasteButton.addActionListener(new ActionListener() {
  			public void actionPerformed(ActionEvent ae) {
  				pasteToTextField(url);
  			}
  		});
  		c.gridx = 3;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(0, 0, 0, 5);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.NONE;
  		urlPanel.add(urlPasteButton, c);
  
  		c.gridx = 1;
  		c.gridy = 3;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(10, 10, 10, 10);
  		c.weightx = 1;
  		c.weighty = 1;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.HORIZONTAL;
  		container.add(urlPanel, c);
  
  		// Notes Row
  		JLabel notesLabel = new JLabel(Translator.translate("notes"));
  		c.gridx = 0;
  		c.gridy = 4;
  		c.anchor = GridBagConstraints.FIRST_LINE_START;
  		c.insets = new Insets(10, 10, 10, 10);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.NONE;
  		container.add(notesLabel, c);
  
  		// This panel will hold the Notes text area and the copy and paste
  		// buttons.
  		JPanel notesPanel = new JPanel(new GridBagLayout());
  
  		notes = new JTextArea(new String(pAccount.getNotes()), 10, 20);
  		if (readOnly) {
  			notes.setEditable(false);
  		}
  		notes.setLineWrap(true); // Enable line wrapping.
  		notes.setWrapStyleWord(true); // Line wrap at whitespace.
  		JScrollPane notesScrollPane = new JScrollPane(notes);
  		c.gridx = 0;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(0, 0, 0, 5);
  		c.weightx = 1;
  		c.weighty = 1;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.BOTH;
  		notesPanel.add(notesScrollPane, c);
  
  		JButton notesCopyButton = new JButton();
  		notesCopyButton.setIcon(Util.loadImage("copy-icon.png"));
  		notesCopyButton.setToolTipText("Copy");
  		notesCopyButton.setEnabled(true);
  		notesCopyButton.setMargin(new Insets(0, 0, 0, 0));
  		notesCopyButton.addActionListener(new ActionListener() {
  			public void actionPerformed(ActionEvent ae) {
  				copyTextArea(notes);
  			}
  		});
  		c.gridx = 1;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.FIRST_LINE_START;
  		c.insets = new Insets(0, 0, 0, 5);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.NONE;
  		notesPanel.add(notesCopyButton, c);
  
  		JButton notesPasteButton = new JButton();
  		notesPasteButton.setIcon(Util.loadImage("paste-icon.png"));
  		notesPasteButton.setToolTipText("Paste");
  		notesPasteButton.setEnabled(!readOnly);
  		notesPasteButton.setMargin(new Insets(0, 0, 0, 0));
  		notesPasteButton.addActionListener(new ActionListener() {
  			public void actionPerformed(ActionEvent ae) {
  				pasteToTextArea(notes);
  			}
  		});
  		c.gridx = 2;
  		c.gridy = 0;
  		c.anchor = GridBagConstraints.FIRST_LINE_START;
  		c.insets = new Insets(0, 0, 0, 5);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.NONE;
  		notesPanel.add(notesPasteButton, c);
  
  		c.gridx = 1;
  		c.gridy = 4;
  		c.anchor = GridBagConstraints.LINE_START;
  		c.insets = new Insets(10, 10, 10, 10);
  		c.weightx = 1;
  		c.weighty = 1;
  		c.gridwidth = 1;
  		c.fill = GridBagConstraints.HORIZONTAL;
  		container.add(notesPanel, c);
  
  		// Seperator Row
  		JSeparator sep = new JSeparator();
  		c.gridx = 0;
  		c.gridy = 5;
  		c.anchor = GridBagConstraints.PAGE_END;
  		c.insets = new Insets(0, 0, 0, 0);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 3;
  		c.fill = GridBagConstraints.HORIZONTAL;
  		container.add(sep, c);
  
  		// Button Row
  		JPanel buttonPanel = new JPanel();
  		JButton okButton = new JButton(Translator.translate("ok"));
  		// Link Enter key to okButton
  		getRootPane().setDefaultButton(okButton);
  		okButton.addActionListener(new ActionListener() {
  			public void actionPerformed(ActionEvent e) {
  				okButtonAction();
  			}
  		});
  		buttonPanel.add(okButton);
  		if (!readOnly) {
  			JButton cancelButton = new JButton(Translator.translate("cancel"));
  			cancelButton.addActionListener(new ActionListener() {
  				public void actionPerformed(ActionEvent e) {
  					closeButtonAction();
  				}
  			});
  			buttonPanel.add(cancelButton);
  		}
  		c.gridx = 0;
  		c.gridy = 6;
  		c.anchor = GridBagConstraints.PAGE_END;
  		c.insets = new Insets(5, 0, 5, 0);
  		c.weightx = 0;
  		c.weighty = 0;
  		c.gridwidth = 3;
  		c.fill = GridBagConstraints.NONE;
  		container.add(buttonPanel, c);
  	} // End AccountDialog constructor
  
  	public boolean okClicked() {
  		return okClicked;
  	} // End okClicked()
  
  	public AccountInformation getAccount() {
  		return pAccount;
  	} // End getAccount()
  
  	private void okButtonAction() {
  
  		// Check if the account name has changed.
  		if (!pAccount.getAccountName().equals(accountName.getText().trim())) {
  			accountChanged = true;
  		}
  
  		// [1375397] Ensure that an account with the supplied name doesn't
  		// already exist.
  		// By checking 'accountNames' we're checking both visible and filtered
  		// accounts
  		//
  		// Only check if an account with the same name exists if the account
  		// name has actually changed
  		if (accountChanged && existingAccounts.indexOf(accountName.getText().trim()) > -1) {
  			JOptionPane.showMessageDialog(parentWindow,
  					Translator.translate("accountAlreadyExistsWithName", accountName.getText().trim()),
  					Translator.translate("accountAlreadyExists"), JOptionPane.ERROR_MESSAGE);
  		} else {
  			// Check for changes
  			if (!pAccount.getUserId().equals(userId.getText())) {
  				accountChanged = true;
  			}
  			if (!pAccount.getPassword().equals(password.getText())) {
  				accountChanged = true;
  			}
  			if (!pAccount.getUrl().equals(url.getText())) {
  				accountChanged = true;
  			}
  			if (!pAccount.getNotes().equals(notes.getText())) {
  				accountChanged = true;
  			}
  
  			pAccount.setAccountName(accountName.getText().trim());
  			pAccount.setUserId(userId.getText());
  			pAccount.setPassword(password.getText());
  			pAccount.setUrl(url.getText());
  			pAccount.setNotes(notes.getText());
  
  			setVisible(false);
  			dispose();
  			okClicked = true;
  		}
  	} // End okButtonAction()
  
  	public boolean getAccountChanged() {
  		return accountChanged;
  	} // End getAccountChanged()
  
  	private void closeButtonAction() {
  		okClicked = false;
  		setVisible(false);
  		dispose();
  	} // End closeButtonAction()
  
  	/**
  	 * This method takes as input the user's preferences about password length,
  	 * including or excluding Escape Characters, and randomly generates a
  	 * password. Then, the method returns the generated password as a String.
  	 *
  	 * @param PassLength
  	 * @param InclEscChars
  	 * @return passwordBuffer.toString()
  	 */
  	private static String GeneratePassword(int PassLength, boolean InclEscChars) {
  		SecureRandom random = new SecureRandom();
  		StringBuffer passwordBuffer = new StringBuffer();
  
  		if (InclEscChars) {
  			for (int i = 0; i < PassLength; i++) {
  				passwordBuffer.append(EXTRA_ALLOWED_CHARS[random.nextInt(EXTRA_ALLOWED_CHARS.length)]);
  			}
  			return passwordBuffer.toString();
  
  		} else {
  			for (int i = 0; i < PassLength; i++) {
  				passwordBuffer.append(ALLOWED_CHARS[random.nextInt(ALLOWED_CHARS.length)]);
  			}
  			return passwordBuffer.toString();
  		}
  	} // End GeneratePassword()
  
  	/**
  	 * This method returns true if the generated password satisfies the criteria
  	 * of a strong password, including or excluding Escape Characters. If not,
  	 * then returns false.
  	 *
  	 * @param Pass
  	 * @param InclEscChars
  	 * @return true or false, depending on strength criteria.
  	 */
  	private static boolean CheckPassStrong(String Pass, boolean InclEscChars) {
  		if (InclEscChars) {
  			if ((InclUpperCase(Pass)) && (InclLowerCase(Pass)) && (InclNumber(Pass)) && (InclEscape(Pass))) {
  				return true;
  			} else {
  				return false;
  			}
  		} else {
  			if ((InclUpperCase(Pass)) && (InclLowerCase(Pass)) && (InclNumber(Pass))) {
  				return true;
  			} else {
  				return false;
  			}
  		}
  	} // End CheckPassStrong()
  
  	/**
  	 * This method returns true if the generated password contains at least one
  	 * Upper Case character. If not, then the method returns false.
  	 *
  	 * @param GeneratedPass
  	 * @return true or false, depending on existence of one upper case letter.
  	 */
  	private static boolean InclUpperCase(String GeneratedPass) {
  		char[] PassWordArray = GeneratedPass.toCharArray();
  		boolean find = false;
  		outerloop: for (int i = 0; i < PassWordArray.length; i++) {
  			for (int j = 0; j < UPPERCASE_CHARS.length; j++) {
  				if (PassWordArray[i] == UPPERCASE_CHARS[j]) {
  					find = true;
  					break outerloop;
  				}
  			}
  		}
  		if (find) {
  			return true;
  		} else {
  			return false;
  		}
  	} // End InclUpperCase()
  
  	/**
  	 * This method returns true if the generated password contains at least one
  	 * Lower Case character. If not, then the method returns false.
  	 *
  	 * @param GeneratedPass
  	 * @return true or false, depending on existence of one lower case letter.
  	 */
  	private static boolean InclLowerCase(String GeneratedPass) {
  		char[] PassWordArray = GeneratedPass.toCharArray();
  		boolean find = false;
  		outerloop: for (int i = 0; i < PassWordArray.length; i++) {
  			for (int j = 0; j < LOWERCASE_CHARS.length; j++) {
  				if (PassWordArray[i] == LOWERCASE_CHARS[j]) {
  					find = true;
  					break outerloop;
  				}
  			}
  		}
  		if (find) {
  			return true;
  		} else {
  			return false;
  		}
  	} // End InclLowerCase()
  
  	/**
  	 * This method returns true if the generated password contains at least one
  	 * Number. If not, then the method returns false.
  	 *
  	 * @param GeneratedPass
  	 * @return true or false, depending on existence of one number.
  	 */
  	private static boolean InclNumber(String GeneratedPass) {
  		char[] PassWordArray = GeneratedPass.toCharArray();
  		boolean find = false;
  		outerloop: for (int i = 0; i < PassWordArray.length; i++) {
  			for (int j = 0; j < NUMBER_CHARS.length; j++) {
  				if (PassWordArray[i] == NUMBER_CHARS[j]) {
  					find = true;
  					break outerloop;
  				}
  			}
  		}
  		if (find) {
  			return true;
  		} else {
  			return false;
  		}
  	} // End InclNumber()
  
  	/**
  	 * This method returns true if the generated password contains at least one
  	 * Escape character. If not, then the method returns false.
  	 *
  	 * @param GeneratedPass
  	 * @return true or false, depending on existence of one escape character.
  	 */
  	private static boolean InclEscape(String GeneratedPass) {
  		char[] PassWordArray = GeneratedPass.toCharArray();
  		boolean find = false;
  		outerloop: for (int i = 0; i < PassWordArray.length; i++) {
  			for (int j = 0; j < PUNCTUATION_CHARS.length; j++) {
  				if (PassWordArray[i] == PUNCTUATION_CHARS[j]) {
  					find = true;
  					break outerloop;
  				}
  			}
  		}
  		if (find) {
  			return true;
  		} else {
  			return false;
  		}
  	} // End InclEscape()
  
  	/**
  	 * This method takes in a JTextField object and then copies the text of that
  	 * text field to the system clipboard.
  	 * 
  	 * @param textField
  	 */
  	public void copyTextField(JTextField textField) {
  		Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
  		StringSelection selected = new StringSelection(textField.getText());
  		clipboard.setContents(selected, selected);
  	}
  
  	/**
  	 * This method takes in a JTextArea object and then copies the selected text
  	 * in that text area to the system clipboard.
  	 * 
  	 * @param textArea
  	 */
  	public void copyTextArea(JTextArea textArea) {
  		Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
  		StringSelection selected = new StringSelection(textArea.getSelectedText());
  		clipboard.setContents(selected, selected);
  	}
  
  	/**
  	 * This method takes in a JTextField object and then sets the text of that
  	 * text field to the contents of the system clipboard.
  	 * 
  	 * @param textField
  	 */
  	public void pasteToTextField(JTextField textField) {
  		String text = "";
  		Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
  		Transferable clipText = clipboard.getContents(null);
  		if ((clipText != null) && clipText.isDataFlavorSupported(DataFlavor.stringFlavor)) {
  			try {
  				text = (String) clipText.getTransferData(DataFlavor.stringFlavor);
  			} catch (UnsupportedFlavorException ex) {
  				ex.printStackTrace();
  			} catch (IOException ex) {
  				ex.printStackTrace();
  			}
  		}
  		textField.setText(text);
  	}
  
  	/**
  	 * This method takes in a JTextArea object and then inserts the contents of
  	 * the system clipboard into that text area at the cursor position.
  	 * 
  	 * @param textArea
  	 */
  	public void pasteToTextArea(JTextArea textArea) {
  		String text = "";
  		Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
  		Transferable clipText = clipboard.getContents(null);
  		if ((clipText != null) && clipText.isDataFlavorSupported(DataFlavor.stringFlavor)) {
  			try {
  				text = (String) clipText.getTransferData(DataFlavor.stringFlavor);
  			} catch (UnsupportedFlavorException ex) {
  				ex.printStackTrace();
  			} catch (IOException ex) {
  				ex.printStackTrace();
  			}
  		}
  		textArea.insert(text, textArea.getCaretPosition());
  		textArea.requestFocus();
  	}
  
  	/**
  	 * Use com.apache.commons.validator library in order to check the validity
  	 * (proper formating, e.x http://www.url.com) of the given URL.
  	 * 
  	 * @param urL
  	 * @return
  	 */
  	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.
  	 * 
  	 * @param url
  	 */
  	private void LaunchSelectedURL(String url) {
  
  		if (Desktop.isDesktopSupported()) {
  			Desktop desktop = Desktop.getDesktop();
  
  			try {
  				desktop.browse(new URI(url));
  			} catch (IOException e) {
  				e.printStackTrace();
  			} catch (URISyntaxException e) {
  				e.printStackTrace();
  			}
  		} else { // Linux and Mac specific code in order to launch url
  			Runtime runtime = Runtime.getRuntime();
  
  			try {
  				runtime.exec("xdg-open " + url);
  			} catch (IOException e) {
  				e.printStackTrace();
  			}
  		}
  	}
  }
  