// Near Infinity - An Infinity Engine Browser and Editor
// Copyright (C) 2001 - 2005 Jon Olav Hauglid
// See LICENSE.txt for license information
package org.infinity.gui;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.infinity.NearInfinity;
import org.infinity.gui.BrowserMenuBar.Bookmark;
import org.infinity.util.SimpleListModel;
/**
* Edit or remove bookmarked games.
*/
public class BookmarkEditor extends JDialog implements ActionListener, FocusListener, ListSelectionListener
{
private final SimpleListModel<Bookmark> modelEntries = new SimpleListModel<Bookmark>();
private final JList<Bookmark> listEntries = new JList<Bookmark>(modelEntries);
private final JButton bUp = new JButton("Up");
private final JButton bDown = new JButton("Down");
private final JButton bRemove = new JButton("Remove");
private final JButton bClear = new JButton("Clear");
private final JButton bOK = new JButton("OK");
private final JButton bCancel = new JButton("Cancel");
private final JTextField tfName = new JTextField();
private final JTextField tfPath = createReadOnlyField(null, true);
private final List<BrowserMenuBar.Bookmark> listBookmarks = new ArrayList<BrowserMenuBar.Bookmark>();
private boolean accepted;
public static List<BrowserMenuBar.Bookmark> editBookmarks(List<BrowserMenuBar.Bookmark> bookmarks)
{
BookmarkEditor dlg = new BookmarkEditor(NearInfinity.getInstance(), bookmarks);
List<BrowserMenuBar.Bookmark> retVal = dlg.getBookmarkList();
dlg.dispose();
dlg = null;
return retVal;
}
private BookmarkEditor(Window owner, List<BrowserMenuBar.Bookmark> bookmarks)
{
super(owner, "Bookmark Editor", Dialog.ModalityType.APPLICATION_MODAL);
init(bookmarks);
}
private void init(List<BrowserMenuBar.Bookmark> bookmarks)
{
setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), this);
getRootPane().getActionMap().put(this, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e)
{
cancel();
}
});
GridBagConstraints gbc = new GridBagConstraints();
listEntries.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
listEntries.addListSelectionListener(this);
// creating bookmark details panel
JPanel pDetails = new JPanel(new GridBagLayout());
JLabel lName = new JLabel("Name:");
JLabel lPath = new JLabel("Path:");
tfName.addFocusListener(this);
gbc = ViewerUtil.setGBC(gbc, 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START,
GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0);
pDetails.add(lName, gbc);
gbc = ViewerUtil.setGBC(gbc, 1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START,
GridBagConstraints.HORIZONTAL, new Insets(0, 8, 0, 0), 0, 0);
pDetails.add(tfName, gbc);
gbc = ViewerUtil.setGBC(gbc, 0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START,
GridBagConstraints.HORIZONTAL, new Insets(8, 0, 0, 0), 0, 0);
pDetails.add(lPath, gbc);
gbc = ViewerUtil.setGBC(gbc, 1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START,
GridBagConstraints.HORIZONTAL, new Insets(8, 8, 0, 0), 0, 0);
pDetails.add(tfPath, gbc);
// creating edit buttons panel
JPanel pEdit = new JPanel(new GridBagLayout());
bUp.setEnabled(false);
bUp.addActionListener(this);
bDown.setEnabled(false);
bDown.addActionListener(this);
bRemove.setEnabled(false);
bRemove.addActionListener(this);
bClear.setEnabled(false);
bClear.addActionListener(this);
gbc = ViewerUtil.setGBC(gbc, 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START,
GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0);
pEdit.add(bUp, gbc);
gbc = ViewerUtil.setGBC(gbc, 0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START,
GridBagConstraints.HORIZONTAL, new Insets(8, 0, 0, 0), 0, 0);
pEdit.add(bDown, gbc);
gbc = ViewerUtil.setGBC(gbc, 0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START,
GridBagConstraints.HORIZONTAL, new Insets(24, 0, 0, 0), 0, 0);
pEdit.add(bRemove, gbc);
gbc = ViewerUtil.setGBC(gbc, 0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START,
GridBagConstraints.HORIZONTAL, new Insets(8, 0, 0, 0), 0, 0);
pEdit.add(bClear, gbc);
gbc = ViewerUtil.setGBC(gbc, 0, 4, 1, 1, 0.0, 1.0, GridBagConstraints.LINE_START,
GridBagConstraints.VERTICAL, new Insets(0, 0, 0, 0), 0, 0);
pEdit.add(new JPanel(), gbc);
// creating dialog buttons panel
JPanel pButtons = new JPanel(new GridBagLayout());
bOK.addActionListener(this);
bCancel.addActionListener(this);
Dimension d = new Dimension();
d.width = Math.max(bOK.getPreferredSize().width, bCancel.getPreferredSize().width);
d.height = Math.max(bOK.getPreferredSize().height, bCancel.getPreferredSize().height);
bOK.setPreferredSize(d);
bCancel.setPreferredSize(d);
gbc = ViewerUtil.setGBC(gbc, 0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START,
GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0);
pButtons.add(new JPanel(), gbc);
gbc = ViewerUtil.setGBC(gbc, 1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START,
GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0);
pButtons.add(bOK, gbc);
gbc = ViewerUtil.setGBC(gbc, 2, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START,
GridBagConstraints.HORIZONTAL, new Insets(0, 8, 0, 0), 0, 0);
pButtons.add(bCancel, gbc);
gbc = ViewerUtil.setGBC(gbc, 3, 0, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START,
GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0);
pButtons.add(new JPanel(), gbc);
JPanel pMain = new JPanel(new GridBagLayout());
JScrollPane spList = new JScrollPane(listEntries);
gbc = ViewerUtil.setGBC(gbc, 0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.LINE_START,
GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0);
pMain.add(spList, gbc);
gbc = ViewerUtil.setGBC(gbc, 1, 0, 1, 1, 0.0, 1.0, GridBagConstraints.LINE_START,
GridBagConstraints.VERTICAL, new Insets(0, 8, 0, 0), 0, 0);
pMain.add(pEdit, gbc);
gbc = ViewerUtil.setGBC(gbc, 0, 1, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START,
GridBagConstraints.HORIZONTAL, new Insets(8, 0, 0, 0), 0, 0);
pMain.add(pDetails, gbc);
gbc = ViewerUtil.setGBC(gbc, 1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START,
GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0);
pMain.add(new JPanel(), gbc);
gbc = ViewerUtil.setGBC(gbc, 0, 2, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START,
GridBagConstraints.HORIZONTAL, new Insets(16, 0, 0, 0), 0, 0);
pMain.add(pButtons, gbc);
// putting all together
setLayout(new GridBagLayout());
gbc = ViewerUtil.setGBC(gbc, 0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER,
GridBagConstraints.BOTH, new Insets(8, 8, 8, 8), 0, 0);
add(pMain, gbc);
initData(bookmarks);
pack();
setMinimumSize(getPreferredSize());
d = new Dimension(getPreferredSize());
d.width = (d.width * 4) / 3;
d.height = (d.height * 4) / 3;
setPreferredSize(d);
pack();
setLocationRelativeTo(getOwner());
setVisible(true);
}
private void initData(List<BrowserMenuBar.Bookmark> bookmarks)
{
// making deep copy of provided list
if (bookmarks != null) {
this.listBookmarks.clear();
for (Iterator<BrowserMenuBar.Bookmark> iter = bookmarks.iterator(); iter.hasNext();) {
try {
this.listBookmarks.add((BrowserMenuBar.Bookmark)iter.next().clone());
} catch (CloneNotSupportedException e) {
// unused
}
}
}
if (listBookmarks != null) {
for (Iterator<BrowserMenuBar.Bookmark> iter = listBookmarks.iterator(); iter.hasNext();) {
modelEntries.addElement(iter.next());
}
if (!modelEntries.isEmpty()) {
listEntries.setSelectedIndex(0);
bRemove.setEnabled(true);
bClear.setEnabled(true);
bUp.setEnabled(false);
bDown.setEnabled(modelEntries.size() > 1);
}
}
}
// Returns the (updated) bookmark list
private List<BrowserMenuBar.Bookmark> getBookmarkList()
{
return accepted() ? listBookmarks : null;
}
private boolean accepted()
{
return accepted;
}
// Called when pressed the OK button
private void accept()
{
// updating bookmark list
listBookmarks.clear();
for (int i = 0, size = modelEntries.size(); i < size; i++) {
listBookmarks.add((BrowserMenuBar.Bookmark)modelEntries.get(i));
}
accepted = true;
setVisible(false);
}
// Called when pressing the Cancel button
private void cancel()
{
accepted = false;
setVisible(false);
}
// Creates a read-only text field, optionally with visible caret
private static JTextField createReadOnlyField(String text, boolean showCaret)
{
JTextField tf = new JTextField();
if (showCaret) {
tf.addFocusListener(new FocusListener() {
@Override
public void focusLost(FocusEvent e)
{
JTextField tf = (JTextField)e.getSource();
tf.getCaret().setVisible(false);
}
@Override
public void focusGained(FocusEvent e)
{
JTextField tf = (JTextField)e.getSource();
tf.getCaret().setVisible(true);
}
});
}
tf.setEditable(false);
tf.setFont(UIManager.getFont("Label.font"));
if (text != null) {
tf.setText(text);
tf.setCaretPosition(0);
}
return tf;
}
private void updateEntry(int index)
{
bUp.setEnabled(index > 0);
bDown.setEnabled(index < modelEntries.size() - 1);
bRemove.setEnabled(index >= 0);
bClear.setEnabled(!modelEntries.isEmpty());
if (index >= 0) {
BrowserMenuBar.Bookmark bookmark = (BrowserMenuBar.Bookmark)modelEntries.get(index);
tfName.setText(bookmark.getName());
tfName.setSelectionStart(0);
tfName.setSelectionEnd(0);
tfPath.setText(bookmark.getPath());
tfPath.setSelectionStart(0);
tfPath.setSelectionEnd(0);
} else {
tfName.setText("");
tfPath.setText("");
}
}
//--------------------- Begin Interface ActionListener ---------------------
@Override
public void actionPerformed(ActionEvent event)
{
if (event.getSource() == bOK) {
accept();
} else if (event.getSource() == bCancel) {
cancel();
} else if (event.getSource() == bUp) {
int oldIdx = listEntries.getSelectedIndex();
if (oldIdx > 0) {
int newIdx = oldIdx - 1;
Bookmark obj = modelEntries.remove(oldIdx);
modelEntries.add(newIdx, obj);
listEntries.setSelectedIndex(newIdx);
updateEntry(newIdx);
}
} else if (event.getSource() == bDown) {
int oldIdx = listEntries.getSelectedIndex();
if (oldIdx >= 0 && oldIdx < modelEntries.size() - 1) {
int newIdx = oldIdx + 1;
Bookmark obj = modelEntries.remove(oldIdx);
modelEntries.add(newIdx, obj);
listEntries.setSelectedIndex(newIdx);
updateEntry(newIdx);
}
} else if (event.getSource() == bRemove) {
int idx = listEntries.getSelectedIndex();
if (idx >= 0) {
modelEntries.remove(idx);
idx = Math.min(idx, modelEntries.size() - 1);
listEntries.setSelectedIndex(idx);
updateEntry(idx);
}
} else if (event.getSource() == bClear) {
if (!modelEntries.isEmpty()) {
if (JOptionPane.showConfirmDialog(this, "Remove all bookmarks?", "Question",
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
modelEntries.clear();
updateEntry(-1);
}
}
}
}
//--------------------- End Interface ActionListener ---------------------
//--------------------- Begin Interface FocusListener ---------------------
@Override
public void focusGained(FocusEvent event)
{
}
@Override
public void focusLost(FocusEvent event)
{
if (event.getSource() == tfName) {
int idx = listEntries.getSelectedIndex();
if (idx >= 0) {
BrowserMenuBar.Bookmark bookmark = (BrowserMenuBar.Bookmark)modelEntries.get(idx);
if (!tfName.getText().trim().isEmpty()) {
// update name in selected entry
bookmark.setName(tfName.getText().trim());
listEntries.repaint();
} else {
// restore name from selected entry
tfName.setText(bookmark.getName());
}
} else {
tfName.setText("");
}
}
}
//--------------------- End Interface FocusListener ---------------------
//--------------------- Begin Interface ListSelectionListener ---------------------
@Override
public void valueChanged(ListSelectionEvent event)
{
if (event.getSource() == listEntries) {
updateEntry(listEntries.getSelectedIndex());
}
}
//--------------------- End Interface ListSelectionListener ---------------------
}