/*
* The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
* for visualizing and manipulating spatial features with geometry and attributes.
*
* Copyright (C) 2003 Vivid Solutions
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* For more information, contact:
*
* Vivid Solutions
* Suite #1A
* 2328 Government Street
* Victoria BC V8T 5G5
* Canada
*
* (250)385-6040
* www.vividsolutions.com
*/
package com.vividsolutions.jump.workbench.ui.addremove;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.border.EtchedBorder;
import com.vividsolutions.jts.util.Assert;
import com.vividsolutions.jump.I18N;
import com.vividsolutions.jump.workbench.ui.GUIUtil;
import com.vividsolutions.jump.workbench.ui.InputChangedFirer;
import com.vividsolutions.jump.workbench.ui.InputChangedListener;
import com.vividsolutions.jump.workbench.ui.images.IconLoader;
/**
* A JPanel that allows the user to move Object's back and forth between
* two JList's.
*/
public class AddRemovePanel extends JPanel {
GridBagLayout gridBagLayout1 = new GridBagLayout();
JPanel jPanel1 = new JPanel();
GridBagLayout gridBagLayout2 = new GridBagLayout();
JButton removeButton = new JButton();
JButton removeAllButton = new JButton();
JButton addButton = new JButton();
JButton moveUpButton = new JButton();
JButton moveDownButton = new JButton();
JButton addAllButton = new JButton();
Border border1;
Border border2;
private JComponent rightLabel = new JLabel();
private JComponent leftLabel = new JLabel();
JScrollPane rightScrollPane = new JScrollPane();
JScrollPane leftScrollPane = new JScrollPane();
private AddRemoveList leftList = new DefaultAddRemoveList();
private AddRemoveList rightList = new DefaultAddRemoveList();
private InputChangedFirer inputChangedFirer = new InputChangedFirer();
public AddRemovePanel(boolean showingUpDownButtons) {
try {
jbInit();
} catch (Exception ex) {
ex.printStackTrace();
}
if (!showingUpDownButtons) {
jPanel1.remove(moveUpButton);
jPanel1.remove(moveDownButton);
}
setLeftList(leftList);
setRightList(rightList);
}
//The spacing between the buttons is according to the Java Look and Feel
//Design Guidelines (http://java.sun.com/products/jlf/at/book/Idioms6.html#57112)
//[Jon Aquino]
private void jbInit() throws Exception {
border1 = new EtchedBorder(EtchedBorder.RAISED, new Color(0, 0, 51), new Color(0, 0, 25));
border2 = new EtchedBorder(EtchedBorder.RAISED, new Color(0, 0, 51), new Color(0, 0, 25));
this.setLayout(gridBagLayout1);
jPanel1.setLayout(gridBagLayout2);
removeButton.setToolTipText(I18N.get("ui.addremove.AddRemovePanel.remove"));
removeAllButton.setToolTipText(I18N.get("ui.addremove.AddRemovePanel.remove-all"));
removeButton.setMargin(new Insets(0, 0, 0, 0));
removeAllButton.setMargin(new Insets(0, 0, 0, 0));
removeButton.setIcon(GUIUtil.toSmallIcon(IconLoader.icon("VCRBack.gif")));
removeAllButton.setIcon(GUIUtil.toSmallIcon(IconLoader.icon("VCRRewind.gif")));
removeButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
removeButton_actionPerformed(e);
}
});
removeAllButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
removeAllButton_actionPerformed(e);
}
});
addButton.setToolTipText(I18N.get("ui.addremove.AddRemovePanel.add"));
moveUpButton.setToolTipText(I18N.get("ui.addremove.AddRemovePanel.move-up"));
moveDownButton.setToolTipText(I18N.get("ui.addremove.AddRemovePanel.move-down"));
addAllButton.setToolTipText(I18N.get("ui.addremove.AddRemovePanel.add-all"));
addButton.setMargin(new Insets(0, 0, 0, 0));
moveUpButton.setMargin(new Insets(0, 0, 0, 0));
moveDownButton.setMargin(new Insets(0, 0, 0, 0));
addAllButton.setMargin(new Insets(0, 0, 0, 0));
addButton.setIcon(GUIUtil.toSmallIcon(IconLoader.icon("VCRForward.gif")));
moveUpButton.setIcon(GUIUtil.toSmallIcon(IconLoader.icon("VCRUp.gif")));
moveDownButton.setIcon(GUIUtil.toSmallIcon(IconLoader.icon("VCRDown.gif")));
addAllButton.setIcon(GUIUtil.toSmallIcon(IconLoader.icon("VCRFastForward.gif")));
addButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
addButton_actionPerformed(e);
}
});
moveUpButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
moveUpButton_actionPerformed(e);
}
});
moveDownButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
moveDownButton_actionPerformed(e);
}
});
addAllButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
addAllButton_actionPerformed(e);
}
});
jPanel1.setMaximumSize(new Dimension(31, 2147483647));
this.add(
rightScrollPane,
new GridBagConstraints(
34,
12,
1,
1,
1.0,
1.0,
GridBagConstraints.CENTER,
GridBagConstraints.BOTH,
new Insets(4, 4, 4, 4),
0,
0));
rightScrollPane.getViewport().add((JComponent) leftList, null);
this.add(
jPanel1,
new GridBagConstraints(
23,
10,
1,
5,
0.0,
1.0,
GridBagConstraints.CENTER,
GridBagConstraints.VERTICAL,
new Insets(0, 4, 0, 4),
0,
0));
jPanel1.add(
removeAllButton,
new GridBagConstraints(
0,
3,
1,
1,
0.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.NONE,
new Insets(0, 0, 17, 0),
0,
0));
jPanel1.add(
removeButton,
new GridBagConstraints(
0,
2,
1,
1,
0.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.NONE,
new Insets(0, 0, 5, 0),
0,
0));
jPanel1.add(
addButton,
new GridBagConstraints(
0,
0,
1,
1,
0.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.NONE,
new Insets(0, 0, 5, 0),
0,
0));
jPanel1.add(
moveUpButton,
new GridBagConstraints(
0,
4,
1,
1,
0.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.NONE,
new Insets(0, 0, 5, 0),
0,
0));
jPanel1.add(
moveDownButton,
new GridBagConstraints(
0,
5,
1,
1,
0.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.NONE,
new Insets(0, 0, 11, 0),
0,
0));
jPanel1.add(
addAllButton,
new GridBagConstraints(
0,
1,
1,
1,
0.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.NONE,
new Insets(0, 0, 11, 0),
0,
0));
this.add(
leftScrollPane,
new GridBagConstraints(
12,
12,
2,
1,
1.0,
1.0,
GridBagConstraints.CENTER,
GridBagConstraints.BOTH,
new Insets(4, 4, 4, 4),
0,
0));
leftScrollPane.getViewport().add((JComponent) leftList, null);
rightScrollPane.getViewport().add((JComponent) rightList, null);
setRightLabel(rightLabel);
setLeftLabel(leftLabel);
}
public void add(InputChangedListener listener) {
inputChangedFirer.add(listener);
}
/**
* Updates the enabled state of the Component's.
*/
public void updateEnabled() {
addButton.setEnabled(!leftList.getSelectedItems().isEmpty());
addAllButton.setEnabled(!leftList.getModel().getItems().isEmpty());
removeButton.setEnabled(!rightList.getSelectedItems().isEmpty());
removeAllButton.setEnabled(!rightList.getModel().getItems().isEmpty());
moveUpButton.setEnabled(!itemsToMoveUp().isEmpty());
moveDownButton.setEnabled(!itemsToMoveDown().isEmpty());
inputChangedFirer.fire();
}
void addAllButton_actionPerformed(ActionEvent e) {
for (Iterator i = leftList.getModel().getItems().iterator(); i.hasNext();) {
Object item = i.next();
rightList.getModel().add(item);
leftList.getModel().remove(item);
}
updateEnabled();
}
void removeAllButton_actionPerformed(ActionEvent e) {
for (Iterator i = rightList.getModel().getItems().iterator(); i.hasNext();) {
Object item = i.next();
rightList.getModel().remove(item);
leftList.getModel().add(item);
}
updateEnabled();
}
void addButton_actionPerformed(ActionEvent e) {
addSelected();
}
private void addSelected() {
for (Iterator i = leftList.getSelectedItems().iterator(); i.hasNext();) {
Object selectedItem = i.next();
rightList.getModel().add(selectedItem);
leftList.getModel().remove(selectedItem);
}
updateEnabled();
}
void moveUpButton_actionPerformed(ActionEvent e) {
move(itemsToMoveUp(), -1);
}
private void move(Collection itemsToMove, int displacement) {
Collection selectedItems = rightList.getSelectedItems();
List items = new ArrayList(rightList.getModel().getItems());
for (Iterator i = itemsToMove.iterator(); i.hasNext();) {
Object item = i.next();
int index = items.indexOf(item);
items.remove(item);
items.add(index + displacement, item);
}
rightList.getModel().setItems(items);
rightList.setSelectedItems(selectedItems);
updateEnabled();
}
void moveDownButton_actionPerformed(ActionEvent e) {
move(itemsToMoveDown(), +1);
}
private Collection itemsToMoveUp() {
return itemsToMoveUp(rightList.getModel().getItems(), rightList.getSelectedItems());
}
private Collection itemsToMoveDown() {
return itemsToMoveDown(rightList.getModel().getItems(), rightList.getSelectedItems());
}
public static Collection itemsToMoveDown(List items, Collection selectedItems) {
List reverseItems = new ArrayList(items);
Collections.reverse(reverseItems);
return itemsToMoveUp(reverseItems, selectedItems);
}
public static Collection itemsToMoveUp(List items, Collection selectedItems) {
int firstUnselectedIndex = firstUnselectedIndex(items, selectedItems);
if (firstUnselectedIndex == -1) {
return new ArrayList();
}
ArrayList itemsToMoveUp = new ArrayList();
for (int i = firstUnselectedIndex; i < items.size(); i++) {
Object item = (Object) items.get(i);
if (selectedItems.contains(item)) {
itemsToMoveUp.add(item);
}
}
return itemsToMoveUp;
}
private static int firstUnselectedIndex(List items, Collection selectedItems) {
for (int i = 0; i < items.size(); i++) {
Object item = (Object) items.get(i);
if (!selectedItems.contains(item)) {
return i;
}
}
return -1;
}
void removeButton_actionPerformed(ActionEvent e) {
removeSelected();
}
private void removeSelected() {
for (Iterator i = rightList.getSelectedItems().iterator(); i.hasNext();) {
Object selectedItem = i.next();
rightList.getModel().remove(selectedItem);
leftList.getModel().add(selectedItem);
}
updateEnabled();
}
public void setLeftText(String newLeftText) {
if (leftLabel instanceof JLabel) {
((JLabel) leftLabel).setText(newLeftText);
} else {
Assert.shouldNeverReachHere();
}
}
public void setRightLabel(JComponent rightLabel) {
remove(rightLabel);
this.rightLabel = rightLabel;
add(
rightLabel,
new GridBagConstraints(
34,
10,
1,
1,
0.0,
0.0,
GridBagConstraints.WEST,
GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0),
0,
0));
initLabelSizes();
}
public void setLeftLabel(JComponent leftLabel) {
remove(leftLabel);
this.leftLabel = leftLabel;
add(
leftLabel,
new GridBagConstraints(
12,
10,
2,
1,
0.0,
0.0,
GridBagConstraints.WEST,
GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0),
0,
0));
initLabelSizes();
}
private void initLabelSizes() {
//Ensure left and right sides have same width [Jon Aquino]
Dimension d =
new Dimension(
(int) Math.max(
leftLabel.getPreferredSize().getWidth(),
rightLabel.getPreferredSize().getWidth()),
(int) Math.max(
leftLabel.getPreferredSize().getHeight(),
rightLabel.getPreferredSize().getHeight()));
leftLabel.setPreferredSize(d);
rightLabel.setPreferredSize(d);
}
public void setRightList(AddRemoveList rightList) {
rightScrollPane.getViewport().remove((JComponent) this.rightList);
this.rightList = rightList;
rightScrollPane.getViewport().add((JComponent) rightList, null);
init(rightList, rightScrollPane);
rightList.add(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e)) {
removeSelected();
}
}
});
}
private void init(AddRemoveList list, JScrollPane scrollPane) {
list.add(new InputChangedListener() {
public void inputChanged() {
updateEnabled();
}
});
//A tip from Jason Ross to ensure that the left and right panels start
//the same size and stay that way when the dialog is resized: simply make
//sure their preferred sizes are initially the same. [Jon Aquino]
scrollPane.setPreferredSize(new Dimension(10, 10));
updateEnabled();
}
public void setLeftList(AddRemoveList leftList) {
leftScrollPane.getViewport().remove((JComponent) this.leftList);
this.leftList = leftList;
leftScrollPane.getViewport().add((JComponent) leftList, null);
init(leftList, leftScrollPane);
leftList.add(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e)) {
addSelected();
}
}
});
}
public void setRightText(String newRightText) {
if (rightLabel instanceof JLabel) {
((JLabel) rightLabel).setText(newRightText);
} else {
Assert.shouldNeverReachHere();
}
}
public List getLeftItems() {
return leftList.getModel().getItems();
}
public List getRightItems() {
return rightList.getModel().getItems();
}
public AddRemoveList getLeftList() {
return leftList;
}
public AddRemoveList getRightList() {
return rightList;
}
}