/*
* @author Dirk Bergstrom
*
* Keyring Desktop Client - Easy password management on your phone or desktop.
* Copyright (C) 2009-2010, Dirk Bergstrom, keyring@otisbean.com
*
* Adapted from KeyringEditor v1.1
* Copyright 2006 Markus Griessnig
* http://www.ict.tuwien.ac.at/keyring/
* Markus graciously gave his assent to release the modified code under the GPLv3.
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.otisbean.keyring.gui;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Arrays;
import java.util.Date;
import java.util.Vector;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JSplitPane;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import com.otisbean.keyring.Item;
import com.otisbean.keyring.Ring;
/**
* This class handles the gui.
*/
public class Editor extends Gui {
private static final boolean DEBUG = true;
// ----------------------------------------------------------------
// variables
// ----------------------------------------------------------------
/**
* Separates levels in an item title for the tree view
*/
protected char SEPARATOR = '/'; // item title separator
/**
* Last directory to load from
*/
File previousDirectory = null; // last directory to load from
/**
* Current loaded keyring database
*/
private String dbFilename = "keyring.json"; // default database to save to
private Ring ring;
private JFrame frame;
private PasswordTimeoutWorker timeoutThread;
// flags
/**
* Show button "Save" only when item text changes (true)
*/
private boolean textFieldChanged = true; // show button save only when text changes
/**
* Show item password in clear text (true)
*/
private boolean showPassword = false;
/**
* True when application is locked
*/
private boolean locked = false;
// ----------------------------------------------------------------
// main -----------------------------------------------------------
// ----------------------------------------------------------------
/**
* main
*
* @param argv Commandline parameters
*/
public static void main(String[] argv) {
String dbFilename = null;
Editor myEditor = new Editor();
myEditor.frame = new JFrame(FRAMETITLE);
myEditor.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// check command line parameters
if(argv.length > 1) {
System.out.println("Usage: java -jar KeyringEditor.jar [keyring-database]");
return;
}
if(argv.length > 0) {
dbFilename = argv[0];
}
// setup gui
try {
myEditor.setupGui(dbFilename);
}
catch(Exception e) {
myEditor.msgError(e, "main", true);
}
}
// ----------------------------------------------------------------
// public ---------------------------------------------------------
// ----------------------------------------------------------------
/**
* Returns filename of the current loaded keyring database.
*
* @return Filename
*/
public String getFilename() {
return this.dbFilename;
}
/**
* Returns separator for title levels.
*
* @return Separator
*/
public char getSeparator() {
return this.SEPARATOR;
}
/**
* Returns reference to class Ring.
*
* @return Reference to class Ring
*/
public Ring getRing() {
return this.ring;
}
public void setRing(Ring ring) {
this.ring = ring;
}
// ----------------------------------------------------------------
// private --------------------------------------------------------
// ----------------------------------------------------------------
/**
* Checks if a file already exists and show warning dialog.
*
* @param filename Filename
*
* @return False if file operation should be cancelled
*/
private boolean fileDoesntExistOrOverwriteConfirmed(File file) {
boolean ok = true;
if (file.exists()) {
int n = JOptionPane.showConfirmDialog(
frame, "File already exists. Continue?",
"Warning",
JOptionPane.YES_NO_OPTION);
if (n == JOptionPane.NO_OPTION) {
ok = false;
}
}
return ok;
}
/**
* Shows a error message.
*
* @param e Exception
* @param info User-defined text
* @param showStack True if Exception Stack Trace should be displayed
*/
private void msgError(Exception e, String info, boolean showStack) {
JOptionPane.showMessageDialog(frame,
info + ": " + e.getMessage(),
"Error",
JOptionPane.ERROR_MESSAGE);
if(showStack || DEBUG) {
e.printStackTrace(System.err);
}
}
/**
* Shows a information message.
*
* @param info User-defined text
*/
private void msgInformation(String info) {
JOptionPane.showMessageDialog(frame,
info,
"Information",
JOptionPane.INFORMATION_MESSAGE);
}
// setupGui -------------------------------------------------------
/**
* Loads menubar, adds ActionListeners, starts PasswordTimeout Thread.
*
* @param dbFilename Keyring database or null
*/
private void setupGui(String dbFilename) throws Exception {
// Function: setup gui
// Parameters: keyring-database
// Returns: -
// MenuBar
JMenuBar myMenuBar = setMenuBar();
frame.setJMenuBar(myMenuBar);
// Layout
JSplitPane mySplitPane = setLayout(this);
frame.setContentPane(mySplitPane);
// MenuBar Listener
openMenuItem.addActionListener(new OpenFileListener(this));
openURLMenuItem.addActionListener(new OpenURLListener(this));
saveAsMenuItem.addActionListener(new SaveAsListener(this));
saveToURLMenuItem.addActionListener(new SaveToURLListener(this));
closeMenuItem.addActionListener(new CloseListener(this));
quitMenuItem.addActionListener(new QuitListener(this));
categoriesMenuItem.addActionListener(new editCategoriesListener(this));
csvMenuItem.addActionListener(new csvListener(this));
aboutMenuItem.addActionListener(new AboutListener(this));
importMenuItem.addActionListener(new ImportListener(this));
newMenuItem.addActionListener(new newListener(this));
// itemPane Listener
currentCategory.addActionListener(new currentCategorySelectionListener(this));
// It's just a dropdown, not really a combo box
currentCategory.setEditable(false);
currentTitle.getDocument().addDocumentListener(new documentListener(this));
currentUser.getDocument().addDocumentListener(new documentListener(this));
currentPassword.getDocument().addDocumentListener(new documentListener(this));
currentUrl.getDocument().addDocumentListener(new documentListener(this));
currentNotes.getDocument().addDocumentListener(new documentListener(this));
// itemListPane Listener
categoryList.addActionListener(new CategorySelectionListener(this));
dynTree.getTree().addTreeSelectionListener(new treeSelectionListener(this));
// buttonPane Listener
newItem.addActionListener(new newItemListener(this));
saveItem.addActionListener(new saveItemListener(this));
delItem.addActionListener(new delItemListener(this));
btnLock.addActionListener(new PasswordLockListener(this));
currentPasswordShow.addActionListener(new PasswordShowListener(this));
// Frame
frame.pack();
frame.setVisible(true);
toggleButtonsAndFields(false, false);
// Passwort Timeout
timeoutThread = new PasswordTimeoutWorker(this);
new Thread(timeoutThread).start();
// load Database
loadDatabase(dbFilename);
}
// loadDatabase ---------------------------------------------------
/**
* Loads a Keyring database and setup gui (buttons, menubar) properly.
*
* @param dbFilename Keyring database or null
*/
private void loadDatabase(String filename) throws Exception {
ring = null;
if (null != filename) {
ring = new Ring();
try {
ring.load(filename);
dbFilename = filename;
/* We only set previousDirectory if dbFilename has a directory,
* which is not the case for URLs. */
File tmpPreviousDirectory = new File(dbFilename).getParentFile();
if (null != tmpPreviousDirectory) {
previousDirectory = tmpPreviousDirectory;
}
}
catch(Exception ex) {
msgError(ex, "Open keyring database", false);
try {
// FIXME This is wrong, prompt for a different file?
loadDatabase(null);
return;
}
catch(Exception ignore) {};
}
// Password dialog
if(checkPassword() == false) {
loadDatabase(null);
return;
}
}
initEditorState(null != ring);
}
/**
* Set state of buttons, menus, etc. according to presence of Ring & dbFilename.
*/
private void initEditorState(boolean dbLoaded) {
String title;
if (dbLoaded) {
title = FRAMETITLE + ": " + null == dbFilename ? "UNSAVED" : dbFilename;
setupCategories(ring.getCategories());
dynTree.populate();
} else {
title = FRAMETITLE;
setupCategories(null);
dynTree.clear();
}
frame.setTitle(title);
// Menu bar items
openMenuItem.setEnabled(! dbLoaded);
openURLMenuItem.setEnabled(! dbLoaded);
saveAsMenuItem.setEnabled(dbLoaded);
saveToURLMenuItem.setEnabled(dbLoaded);
closeMenuItem.setEnabled(dbLoaded);
csvMenuItem.setEnabled(dbLoaded);
categoriesMenuItem.setEnabled(dbLoaded);
importMenuItem.setEnabled(! dbLoaded);
toggleButtonsAndFields(false, dbLoaded);
setBtnLock(false, dbLoaded);
}
/**
* Enable buttons according to loaded database.
*
* @param enabled True if database is loaded
* @param newItemEnabled True if the "new item" button should be enabled
*/
private void toggleButtonsAndFields(boolean enabled, boolean newItemEnabled) {
delItem.setEnabled(false);
saveItem.setEnabled(false);
saveItem.setBackground(null);
currentCategory.setEnabled(enabled);
currentTitle.setEditable(enabled);
currentUser.setEditable(enabled);
currentPassword.setEditable(enabled);
currentUrl.setEditable(enabled);
currentNotes.setEditable(enabled);
newItem.setEnabled(newItemEnabled);
}
/**
* Enable button lock according to loaded database and status of password timeout.
*
* @param locked True if application is locked
* @param enabled True if button "Lock" should be enabled
*/
private void setBtnLock(boolean locked, boolean enabled) {
btnLock.setText(locked ? "Unlock" : "Lock");
btnLock.setEnabled(enabled);
this.locked = locked;
saveItem.setBackground(null);
}
// categories -----------------------------------------------------
/**
* Setup category filter combobox.
*
* @param myCategories Categories loaded with Keyring database
*/
private void setupCategories(Vector<String> myCategories) {
// categoryList
Vector<String> displayCategories;
if (null != myCategories) {
displayCategories = new Vector<String>(myCategories);
} else {
displayCategories = new Vector<String>();
}
displayCategories.add(0, "All");
categoryList.setModel(new DefaultComboBoxModel(displayCategories));
// currentCategory
Vector<String> currentCategories;
if (null != myCategories) {
currentCategories = new Vector<String>(myCategories);
} else {
currentCategories = new Vector<String>();
}
currentCategory.setModel(new DefaultComboBoxModel(currentCategories));
}
// password -------------------------------------------------------
/**
* Show password dialog and set Keyring database password.
*
* @return False if dialog cancelled (Boolean)
*/
private boolean checkPassword() {
char[] password = getPasswordFromDialog();
if (null == password) {
return false;
}
boolean retval;
try {
if (ring.validatePassword(password)) {
timeoutThread.restartTimeout();
retval = true;
} else {
msgInformation("Invalid Password");
timeoutThread.setTimeout(); // timed out
retval = false;
}
}
catch(Exception e) {
msgError(e, "Error processing password", false);
timeoutThread.setTimeout(); // timed out
retval = false;
}
// Erase password from memory
Arrays.fill(password, ' ');
return retval;
}
/**
* Show password dialog.
*
* @return Password (null if dialog canceled).
*/
private char[] getPasswordFromDialog() {
PasswordDialog pwdDlg = new PasswordDialog(frame);
pwdDlg.pack();
pwdDlg.setVisible(true);
return pwdDlg.getPassword();
}
// showItem ------------------------------------------------------
/**
* Show item and check password timeout.
*/
private void showItem() {
DefaultMutableTreeNode node = dynTree.getLastNode();
if (locked == true || null == ring) {
return;
}
try {
Date ende = timeoutThread.getEndDate();
if (null == ende) {
// timed out
clearItem();
setBtnLock(true, true);
toggleButtonsAndFields(false, false);
return;
} else {
timeoutThread.restartTimeout();
}
if(node == null || !(node.isLeaf()) || node.isRoot()) {
// no item
clearItem();
toggleButtonsAndFields(false, true);
return;
}
Object nodeInfo = node.getUserObject();
Item item = (Item) nodeInfo;
// set text fields according to item
// if categoryname was deleted, show first category "no category"
if (currentCategory.getItemCount() > item.getCategoryId()) {
currentCategory.setSelectedIndex(item.getCategoryId());
}
else {
currentCategory.setSelectedIndex(0); // no category
}
currentTitle.setText(item.getTitle());
currentUser.setText(item.getUsername());
currentNotes.setText(item.getNotes());
currentPassword.setText(item.getPass());
currentUrl.setText(item.getUrl());
// FIXME This is sleazy and ugly
dateLabel.setText("Created: " + ring.formatDate(item.getCreated(), false) +
" | Changed: " + ring.formatDate(item.getChanged(), false) +
" | Viewed: " + ring.formatDate(item.getViewed(), false));
// initialize buttons
textFieldChanged = false;
toggleButtonsAndFields(true, true);
}
catch(Exception e) {
msgError(e, "showItem", true);
try {
// FIXME I don't think this makes sense
loadDatabase(null);
}
catch(Exception ignore) {};
}
}
/**
* Clear item text fields.
*/
private void clearItem() {
if (currentCategory.getItemCount() > 0) {
currentCategory.setSelectedIndex(0);
}
currentTitle.setText("");
currentUser.setText("");
currentPassword.setText("");
currentUrl.setText("");
dateLabel.setText("");
currentNotes.setText("");
}
/**
* Call when an item field is changed to update GUI state.
*
* Enables the "save item" button, turns it green, and sets the
* textFieldChanged flag.
*/
private void noticeFieldChange() {
if (! textFieldChanged && ! locked) {
textFieldChanged = true;
saveItem.setEnabled(true);
saveItem.setBackground(Color.GREEN);
}
}
// ----------------------------------------------------------------
// listener menubar -----------------------------------------------
// ----------------------------------------------------------------
/**
* MenuItem Open: show a File dialog and load a Keyring JSON database.
*/
public class OpenFileListener implements ActionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
protected OpenFileListener(Editor editor) {
this.editor = editor;
}
/**
* This method opens a file dialog and loads the choosen database.
*
* @param e the ActionEvent to process
*/
public void actionPerformed(ActionEvent e) {
JFileChooser chooser = new JFileChooser();
chooser.setDialogTitle("Open Keyring database");
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
chooser.setMultiSelectionEnabled(false);
chooser.setCurrentDirectory(previousDirectory);
int returnVal = chooser.showOpenDialog(editor.frame);
if(returnVal == JFileChooser.APPROVE_OPTION) {
try {
File selectedFile = chooser.getSelectedFile();
previousDirectory = selectedFile.getParentFile();
dbFilename = selectedFile.getCanonicalPath();
editor.loadDatabase(dbFilename);
}
catch(Exception ex) {
msgError(ex, "Open Keyring database", false);
try {
editor.loadDatabase(null);
}
catch(Exception ignore) {};
}
}
}
}
/**
* MenuItem Open URL: show a simple dialog and load a Keyring JSON database
* from a URL.
*/
public class OpenURLListener implements ActionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
protected OpenURLListener(Editor editor) {
this.editor = editor;
}
/**
* This method opens a simple dialog and loads the choosen database.
*
* @param e the ActionEvent to process
*/
public void actionPerformed(ActionEvent e) {
String urlval = null != dbFilename && dbFilename.startsWith("http") ?
dbFilename : "";
String url = (String) JOptionPane.showInputDialog(
frame,
"URL (must start with \"http\"):",
"Load from URL",
JOptionPane.PLAIN_MESSAGE,
null,
null,
urlval);
if (null != url) {
try {
editor.loadDatabase(url);
}
catch(Exception ex) {
msgError(ex, "Open Keyring database", false);
try {
editor.loadDatabase(null);
}
catch(Exception ignore) {};
}
}
}
}
/**
* MenuItem Close: close Keyring database.
*/
public class CloseListener implements ActionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
protected CloseListener(Editor editor) {
this.editor = editor;
}
/**
* This method closes the loaded database.
*
* @param e the ActionEvent to process
*/
public void actionPerformed(ActionEvent e) {
try {
editor.loadDatabase(null);
}
catch(Exception ignore) {};
}
}
/**
* MenuItem Quit: exit Application.
*/
public class QuitListener implements ActionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
protected QuitListener(Editor editor) {
this.editor = editor;
}
/**
* This method ends the application.
*
* @param e the ActionEvent to process
*/
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
/**
* MenuItem Edit categories: shows the categories dialog for editing category-names.
*/
public class editCategoriesListener implements ActionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
protected editCategoriesListener(Editor editor) {
this.editor = editor;
}
/**
* This method opens the categories dialog and updates the category combo boxes.
*
* @param e the ActionEvent to process
*/
public void actionPerformed(ActionEvent e) {
msgInformation("Category editing not yet supported");
return;
/* FIXME Implement this stuff!
if (locked == true) {
msgInformation("Unlock application first.");
return;
}
// show category dialog
CategoriesDialog catDialog = new CategoriesDialog(frame, ring.getCategories());
catDialog.pack();
catDialog.setVisible(true);
// update category combo boxes
Vector<String> newCategories = catDialog.getNewCategories();
if (null != newCategories) {
// changed categories
setupCategories(newCategories);
//ring.setCategories(newCategories);
// save database
try {
editor.ring.save(dbFilename);
}
catch(Exception ex) {
msgError(ex, "Could not save entries to " + dbFilename, false);
}
}
*/
}
}
/**
* MenuItem Save database to csv: save the loaded Keyring database as a CSV file.
*/
public class csvListener implements ActionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
protected csvListener(Editor editor) {
this.editor = editor;
}
/**
* This method opens a file dialog and saves the database entries to a csv file.
*
* @param e the ActionEvent to process
*/
public void actionPerformed(ActionEvent e) {
if(locked == true) {
msgInformation("Unlock application first.");
return;
}
// show File dialog
JFileChooser chooser = new JFileChooser();
chooser.setDialogTitle("Save Keyring database to CSV-File");
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
chooser.setMultiSelectionEnabled(false);
chooser.setCurrentDirectory(previousDirectory);
int returnVal = chooser.showSaveDialog(editor.frame);
File selectedFile = chooser.getSelectedFile();
if(returnVal == JFileChooser.APPROVE_OPTION) {
try {
previousDirectory = selectedFile.getParentFile();
String csvFilename = selectedFile.getCanonicalPath();
// check if file exists
boolean ok = fileDoesntExistOrOverwriteConfirmed(selectedFile);
if(ok == true) {
// save entries to csv file
editor.ring.exportToCSV(csvFilename);
msgInformation("Entries saved to: " + csvFilename);
}
}
catch(Exception ex) {
msgError(ex, "Could not save entries to " +
selectedFile.getAbsolutePath(), false);
}
}
}
}
/**
* MenuItem Save As: save the loaded Keyring database to specified file.
*/
public class SaveAsListener implements ActionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
protected SaveAsListener(Editor editor) {
this.editor = editor;
}
/**
* This method opens a file dialog and saves the database entries to a csv file.
*
* @param e the ActionEvent to process
*/
public void actionPerformed(ActionEvent e) {
if(locked == true) {
msgInformation("Unlock application first.");
return;
}
// show File dialog
JFileChooser chooser = new JFileChooser();
chooser.setDialogTitle("Save Keyring database");
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
chooser.setMultiSelectionEnabled(false);
chooser.setCurrentDirectory(previousDirectory);
int returnVal = chooser.showSaveDialog(editor.frame);
File selectedFile = chooser.getSelectedFile();
if(returnVal == JFileChooser.APPROVE_OPTION) {
try {
previousDirectory = selectedFile.getParentFile();
String filename = selectedFile.getCanonicalPath();
if (fileDoesntExistOrOverwriteConfirmed(selectedFile)) {
// save entries to csv file
editor.ring.save(filename);
dbFilename = filename;
// FIXME set window title & dyntree root to reflect new filename
msgInformation("Keyring saved to: " + filename);
}
}
catch(Exception ex) {
msgError(ex, "Could not save entries to " +
selectedFile.getAbsolutePath(), false);
}
}
}
}
/**
* MenuItem Save As: save the loaded Keyring database to specified file.
*/
public class SaveToURLListener implements ActionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
protected SaveToURLListener(Editor editor) {
this.editor = editor;
}
/**
* This method opens a file dialog and saves the database entries to a csv file.
*
* @param e the ActionEvent to process
*/
public void actionPerformed(ActionEvent e) {
if(locked == true) {
msgInformation("Unlock application first.");
return;
}
String urlval = null != dbFilename && dbFilename.startsWith("http") ?
dbFilename : "";
String url = (String) JOptionPane.showInputDialog(
frame,
"URL (must start with \"http\"):",
"Load from URL",
JOptionPane.PLAIN_MESSAGE,
null,
null,
urlval);
if (null != url) {
try {
editor.ring.save(url);
dbFilename = url;
// FIXME set window title & dyntree root to reflect new URL
msgInformation("Keyring saved to: " + url);
}
catch(Exception ex) {
msgError(ex, "Could not save entries to " +
url, false);
}
}
}
}
/**
* MenuItem Import: show import dialog and load new database.
*/
public class ImportListener implements ActionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
protected ImportListener(Editor editor) {
this.editor = editor;
}
/**
* This method opens the import dialog and closes the loaded database.
*
* @param e the ActionEvent to process
*/
public void actionPerformed(ActionEvent e) {
// show import dialog
ImportDialog importDialog = new ImportDialog(editor.frame, editor);
importDialog.pack();
importDialog.setVisible(true);
if(importDialog.getCancelled() == false) {
msgInformation("Database imported.");
initEditorState(true);
}
}
}
/**
* MenuItem New empty database: generates a new empty database
*/
public class newListener implements ActionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
protected newListener(Editor editor) {
this.editor = editor;
}
/**
* This method opens a file dialog and generates a new minimal database.
*
* FIXME this is just totally wrong.
*
* @param e the ActionEvent to process
*/
public void actionPerformed(ActionEvent e) {
msgInformation("Creating a new db not currently supported.");
return;
/* FIXME Implement this stuff!
if(locked == true) {
msgInformation("Unlock application first.");
return;
}
try {
ring = new Ring();
dbFilename = "";
msgInformation("Empty database generated.");
}
catch(Exception ex) {
msgError(ex, "Could not generate new database.", false);
}
*/
}
}
/**
* MenuItem About: show Copyright information.
*/
public class AboutListener implements ActionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
protected AboutListener(Editor editor) {
this.editor = editor;
}
/**
* This method shows a copyright information dialog.
*
* FIXME update this.
*
* @param e the ActionEvent to process
*/
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(editor.frame,
Gui.FRAMETITLE + " " + "v" + Gui.VERSION +
"\n\nCopyright 2010 Dirk Bergstrom <keyring@otisbean.com>\n" +
"http://otisbean.com/keyring/\n\n" +
"Keyring Desktop is based on:\n" +
"KeyringEditor v1.1\n" +
"Copyright 2006 Markus Griessnig <markus.griessnig@gmx.at>\n\n" +
"This program is free software: you can redistribute it and/or modify\n" +
"it under the terms of the GNU General Public License as published by\n" +
"the Free Software Foundation, either version 3 of the License, or\n" +
"(at your option) any later version.\n\n" +
"This program is distributed in the hope that it will be useful,\n" +
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +
"GNU General Public License for more details.\n\n" +
"You should have received a copy of the GNU General Public License\n" +
"along with this program. If not, see <http://www.gnu.org/licenses/>.",
"About",
JOptionPane.INFORMATION_MESSAGE);
}
}
// ----------------------------------------------------------------
// listener buttons -----------------------------------------------
// ----------------------------------------------------------------
// new
/**
* Button New: show edit dialog and save new item to database.
*/
public class newItemListener implements ActionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
protected newItemListener(Editor editor) {
this.editor = editor;
}
/**
* This method opens the new item dialog and and saves the new item to database.
*
* @param e the ActionEvent to process
*/
public void actionPerformed(ActionEvent e) {
// show edit dialog
NewItemDialog editDlg = new NewItemDialog(editor.frame, editor.ring.getCategories());
editDlg.pack();
editDlg.setVisible(true);
Object[] buffer = editDlg.getNewItem();
try {
// new item
if(buffer[0] != null) {
/* Edit dialog returns (All String except category is Integer)
* returnParameter[0] = category
* returnParameter[1] = title
* returnParameter[2] = user
* returnParameter[3] = password
* returnParameter[4] = url
* returnParameter[5] = notes
*
* Item expects
* String username,
* String pass,
* String url,
* String notes,
* String title,
* int categoryId
*/
Item myItem = new Item(
editor.ring,
(String) buffer[2],
(String) buffer[3],
(String) buffer[4],
(String) buffer[5],
(String) buffer[1],
((Integer) buffer[0]).intValue()
);
// register new item to vector entries
editor.ring.addItem(myItem);
// update tree view
editor.dynTree.populate();
// save database
editor.ring.save(dbFilename);
// show new item
editor.dynTree.show(myItem);
msgInformation("Entries saved to: " + editor.dbFilename);
}
}
catch(Exception ex) {
msgError(ex, "newItemListener", true);
}
}
}
// save
/**
* Button Save: save changed item to database.
*/
public class saveItemListener implements ActionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
public saveItemListener(Editor editor) {
this.editor = editor;
}
/**
* This method saves a changed item to database.
*
* @param e the ActionEvent to process
*/
public void actionPerformed(ActionEvent e) {
DefaultMutableTreeNode node = editor.dynTree.getLastNode();
try {
// last selected tree node
if(node != null) {
// get updated item
Item myItem = editor.dynTree.getItem(node);
// save changes
myItem.setTitle(editor.currentTitle.getText());
myItem.setUsername(editor.currentUser.getText());
myItem.setPass(String.valueOf(editor.currentPassword.getPassword()));
myItem.setUrl(editor.currentUrl.getText());
myItem.setNotes(editor.currentNotes.getText());
myItem.setCategoryId(editor.currentCategory.getSelectedIndex());
// update tree view
editor.dynTree.populate();
// save database
editor.ring.save(dbFilename);
// Redisplay the item
editor.dynTree.show(myItem);
editor.showItem();
msgInformation("Entries saved to: " + editor.dbFilename);
}
}
catch(Exception ex) {
msgError(ex, "saveItemListener", true);
}
}
}
// del
/**
* Button Delete: delete current item.
*/
public class delItemListener implements ActionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
public delItemListener(Editor editor) {
this.editor = editor;
}
/**
* This method removes a item from database.
*
* @param e the ActionEvent to process
*/
public void actionPerformed(ActionEvent e) {
DefaultMutableTreeNode node = editor.dynTree.getLastNode();
if(node != null) {
Item myItem = editor.dynTree.getItem(node);
// delete item
editor.ring.removeItem(myItem);
// update tree view
editor.dynTree.populate();
// save changes
try {
editor.ring.save(dbFilename);
msgInformation("Item " + myItem.getTitle() + " deleted. Database " + editor.dbFilename + " updated.");
}
catch(Exception ex) {
msgError(ex, "delItemListener", false);
}
}
}
}
// ----------------------------------------------------------------
// listener -------------------------------------------------------
// ----------------------------------------------------------------
// textfields
/**
* DocumentListener: check if item is updated and set button "Save" according.
*/
public class documentListener implements DocumentListener {
protected Editor editor;
protected documentListener(Editor editor) {
this.editor = editor;
}
public void insertUpdate(DocumentEvent e) {
updateLog(e, "insert");
}
public void removeUpdate(DocumentEvent e) {
updateLog(e, "remove");
}
public void changedUpdate(DocumentEvent e) {
updateLog(e, "changed");
}
public void updateLog(DocumentEvent e, String action) {
noticeFieldChange();
}
}
// tree
/**
* TreeSelectionListener: show selected item.
*/
public class treeSelectionListener implements TreeSelectionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
protected treeSelectionListener(Editor editor) {
this.editor = editor;
}
/**
* This method shows the selected item.
*
* @param e the ActionEvent to process
*/
public void valueChanged(TreeSelectionEvent e) {
editor.showItem();
}
}
/**
* CategorySelectionListener: filter tree view according to selected category.
*/
public class CategorySelectionListener implements ActionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
public CategorySelectionListener(Editor editor) {
this.editor = editor;
}
/**
* This method filters the tree view according to selected category.
*
* @param e the ActionEvent to process
*/
public void actionPerformed(ActionEvent e) {
editor.dynTree.setCategoryFilter(editor.categoryList.getSelectedIndex());
editor.showItem();
}
}
/**
* currentCategorySelectionListener: check if item category is changed an set button "Save" according.
*/
public class currentCategorySelectionListener implements ActionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
public currentCategorySelectionListener(Editor editor) {
this.editor = editor;
}
/**
* This method sets button "Save" according to state of variable locked and textFieldChanged.
*
* @param e the ActionEvent to process
*/
public void actionPerformed(ActionEvent e) {
noticeFieldChange();
}
}
/**
* PasswordShowListener: show item password in clear text according to check box "Hide passwords?"
*/
public class PasswordShowListener implements ActionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
protected PasswordShowListener(Editor editor) {
this.editor = editor;
}
/**
* This method shows password in clear text according to variable showPassword.
*
* @param e the ActionEvent to process
*/
public void actionPerformed(ActionEvent e) {
if(showPassword == false) {
showPassword = true;
editor.currentPassword.setEchoChar('\0'); // show password in plaintext
}
else {
showPassword = false;
editor.currentPassword.setEchoChar('*');
}
}
}
/**
* Button Lock / Unlock: set buttons according to variable locked.
*/
public class PasswordLockListener implements ActionListener {
protected Editor editor;
/**
* Default constructor.
*
* @param editor Reference to class Editor
*/
protected PasswordLockListener(Editor editor) {
this.editor = editor;
}
/**
* This method sets the button "Lock / Unlock" according to variable locked.
*
* @param e the ActionEvent to process
*/
public void actionPerformed(ActionEvent e) {
if(editor.locked == false) {
editor.setBtnLock(true, true);
editor.toggleButtonsAndFields(false, false);
editor.clearItem();
}
else {
if(editor.checkPassword() == true) {
editor.setBtnLock(false, true);
editor.showItem();
}
}
}
}
}