001: /*
002: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
003: * for visualizing and manipulating spatial features with geometry and attributes.
004: *
005: * Copyright (C) 2003 Vivid Solutions
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: *
021: * For more information, contact:
022: *
023: * Vivid Solutions
024: * Suite #1A
025: * 2328 Government Street
026: * Victoria BC V8T 5G5
027: * Canada
028: *
029: * (250)385-6040
030: * www.vividsolutions.com
031: */
032:
033: package com.vividsolutions.jump.workbench.ui.addremove;
034:
035: import java.awt.Color;
036: import java.awt.Dimension;
037: import java.awt.GridBagConstraints;
038: import java.awt.GridBagLayout;
039: import java.awt.Insets;
040: import java.awt.event.ActionEvent;
041: import java.awt.event.MouseAdapter;
042: import java.awt.event.MouseEvent;
043: import java.util.ArrayList;
044: import java.util.Collection;
045: import java.util.Collections;
046: import java.util.Iterator;
047: import java.util.List;
048:
049: import javax.swing.JButton;
050: import javax.swing.JComponent;
051: import javax.swing.JLabel;
052: import javax.swing.JPanel;
053: import javax.swing.JScrollPane;
054: import javax.swing.SwingUtilities;
055: import javax.swing.border.Border;
056: import javax.swing.border.EtchedBorder;
057:
058: import com.vividsolutions.jts.util.Assert;
059: import com.vividsolutions.jump.I18N;
060: import com.vividsolutions.jump.workbench.ui.GUIUtil;
061: import com.vividsolutions.jump.workbench.ui.InputChangedFirer;
062: import com.vividsolutions.jump.workbench.ui.InputChangedListener;
063: import com.vividsolutions.jump.workbench.ui.images.IconLoader;
064:
065: /**
066: * A JPanel that allows the user to move Object's back and forth between
067: * two JList's.
068: */
069: public class AddRemovePanel extends JPanel {
070: GridBagLayout gridBagLayout1 = new GridBagLayout();
071: JPanel jPanel1 = new JPanel();
072: GridBagLayout gridBagLayout2 = new GridBagLayout();
073: JButton removeButton = new JButton();
074: JButton removeAllButton = new JButton();
075: JButton addButton = new JButton();
076: JButton moveUpButton = new JButton();
077: JButton moveDownButton = new JButton();
078: JButton addAllButton = new JButton();
079: Border border1;
080: Border border2;
081: private JComponent rightLabel = new JLabel();
082: private JComponent leftLabel = new JLabel();
083: JScrollPane rightScrollPane = new JScrollPane();
084: JScrollPane leftScrollPane = new JScrollPane();
085: private AddRemoveList leftList = new DefaultAddRemoveList();
086: private AddRemoveList rightList = new DefaultAddRemoveList();
087: private InputChangedFirer inputChangedFirer = new InputChangedFirer();
088:
089: public AddRemovePanel(boolean showingUpDownButtons) {
090: try {
091: jbInit();
092: } catch (Exception ex) {
093: ex.printStackTrace();
094: }
095:
096: if (!showingUpDownButtons) {
097: jPanel1.remove(moveUpButton);
098: jPanel1.remove(moveDownButton);
099: }
100:
101: setLeftList(leftList);
102: setRightList(rightList);
103: }
104:
105: //The spacing between the buttons is according to the Java Look and Feel
106: //Design Guidelines (http://java.sun.com/products/jlf/at/book/Idioms6.html#57112)
107: //[Jon Aquino]
108: private void jbInit() throws Exception {
109: border1 = new EtchedBorder(EtchedBorder.RAISED, new Color(0, 0,
110: 51), new Color(0, 0, 25));
111: border2 = new EtchedBorder(EtchedBorder.RAISED, new Color(0, 0,
112: 51), new Color(0, 0, 25));
113: this .setLayout(gridBagLayout1);
114: jPanel1.setLayout(gridBagLayout2);
115: removeButton.setToolTipText(I18N
116: .get("ui.addremove.AddRemovePanel.remove"));
117: removeAllButton.setToolTipText(I18N
118: .get("ui.addremove.AddRemovePanel.remove-all"));
119: removeButton.setMargin(new Insets(0, 0, 0, 0));
120: removeAllButton.setMargin(new Insets(0, 0, 0, 0));
121: removeButton.setIcon(GUIUtil.toSmallIcon(IconLoader
122: .icon("VCRBack.gif")));
123: removeAllButton.setIcon(GUIUtil.toSmallIcon(IconLoader
124: .icon("VCRRewind.gif")));
125: removeButton
126: .addActionListener(new java.awt.event.ActionListener() {
127: public void actionPerformed(ActionEvent e) {
128: removeButton_actionPerformed(e);
129: }
130: });
131: removeAllButton
132: .addActionListener(new java.awt.event.ActionListener() {
133: public void actionPerformed(ActionEvent e) {
134: removeAllButton_actionPerformed(e);
135: }
136: });
137: addButton.setToolTipText(I18N
138: .get("ui.addremove.AddRemovePanel.add"));
139: moveUpButton.setToolTipText(I18N
140: .get("ui.addremove.AddRemovePanel.move-up"));
141: moveDownButton.setToolTipText(I18N
142: .get("ui.addremove.AddRemovePanel.move-down"));
143: addAllButton.setToolTipText(I18N
144: .get("ui.addremove.AddRemovePanel.add-all"));
145: addButton.setMargin(new Insets(0, 0, 0, 0));
146: moveUpButton.setMargin(new Insets(0, 0, 0, 0));
147: moveDownButton.setMargin(new Insets(0, 0, 0, 0));
148: addAllButton.setMargin(new Insets(0, 0, 0, 0));
149: addButton.setIcon(GUIUtil.toSmallIcon(IconLoader
150: .icon("VCRForward.gif")));
151: moveUpButton.setIcon(GUIUtil.toSmallIcon(IconLoader
152: .icon("VCRUp.gif")));
153: moveDownButton.setIcon(GUIUtil.toSmallIcon(IconLoader
154: .icon("VCRDown.gif")));
155: addAllButton.setIcon(GUIUtil.toSmallIcon(IconLoader
156: .icon("VCRFastForward.gif")));
157: addButton
158: .addActionListener(new java.awt.event.ActionListener() {
159: public void actionPerformed(ActionEvent e) {
160: addButton_actionPerformed(e);
161: }
162: });
163: moveUpButton
164: .addActionListener(new java.awt.event.ActionListener() {
165: public void actionPerformed(ActionEvent e) {
166: moveUpButton_actionPerformed(e);
167: }
168: });
169: moveDownButton
170: .addActionListener(new java.awt.event.ActionListener() {
171: public void actionPerformed(ActionEvent e) {
172: moveDownButton_actionPerformed(e);
173: }
174: });
175:
176: addAllButton
177: .addActionListener(new java.awt.event.ActionListener() {
178: public void actionPerformed(ActionEvent e) {
179: addAllButton_actionPerformed(e);
180: }
181: });
182: jPanel1.setMaximumSize(new Dimension(31, 2147483647));
183: this .add(rightScrollPane, new GridBagConstraints(34, 12, 1, 1,
184: 1.0, 1.0, GridBagConstraints.CENTER,
185: GridBagConstraints.BOTH, new Insets(4, 4, 4, 4), 0, 0));
186: rightScrollPane.getViewport().add((JComponent) leftList, null);
187: this .add(jPanel1, new GridBagConstraints(23, 10, 1, 5, 0.0,
188: 1.0, GridBagConstraints.CENTER,
189: GridBagConstraints.VERTICAL, new Insets(0, 4, 0, 4), 0,
190: 0));
191: jPanel1
192: .add(removeAllButton, new GridBagConstraints(0, 3, 1,
193: 1, 0.0, 0.0, GridBagConstraints.CENTER,
194: GridBagConstraints.NONE,
195: new Insets(0, 0, 17, 0), 0, 0));
196: jPanel1.add(removeButton, new GridBagConstraints(0, 2, 1, 1,
197: 0.0, 0.0, GridBagConstraints.CENTER,
198: GridBagConstraints.NONE, new Insets(0, 0, 5, 0), 0, 0));
199: jPanel1.add(addButton, new GridBagConstraints(0, 0, 1, 1, 0.0,
200: 0.0, GridBagConstraints.CENTER,
201: GridBagConstraints.NONE, new Insets(0, 0, 5, 0), 0, 0));
202: jPanel1.add(moveUpButton, new GridBagConstraints(0, 4, 1, 1,
203: 0.0, 0.0, GridBagConstraints.CENTER,
204: GridBagConstraints.NONE, new Insets(0, 0, 5, 0), 0, 0));
205: jPanel1
206: .add(moveDownButton, new GridBagConstraints(0, 5, 1, 1,
207: 0.0, 0.0, GridBagConstraints.CENTER,
208: GridBagConstraints.NONE,
209: new Insets(0, 0, 11, 0), 0, 0));
210:
211: jPanel1
212: .add(addAllButton, new GridBagConstraints(0, 1, 1, 1,
213: 0.0, 0.0, GridBagConstraints.CENTER,
214: GridBagConstraints.NONE,
215: new Insets(0, 0, 11, 0), 0, 0));
216: this .add(leftScrollPane, new GridBagConstraints(12, 12, 2, 1,
217: 1.0, 1.0, GridBagConstraints.CENTER,
218: GridBagConstraints.BOTH, new Insets(4, 4, 4, 4), 0, 0));
219: leftScrollPane.getViewport().add((JComponent) leftList, null);
220: rightScrollPane.getViewport().add((JComponent) rightList, null);
221: setRightLabel(rightLabel);
222: setLeftLabel(leftLabel);
223: }
224:
225: public void add(InputChangedListener listener) {
226: inputChangedFirer.add(listener);
227: }
228:
229: /**
230: * Updates the enabled state of the Component's.
231: */
232: public void updateEnabled() {
233: addButton.setEnabled(!leftList.getSelectedItems().isEmpty());
234: addAllButton.setEnabled(!leftList.getModel().getItems()
235: .isEmpty());
236: removeButton
237: .setEnabled(!rightList.getSelectedItems().isEmpty());
238: removeAllButton.setEnabled(!rightList.getModel().getItems()
239: .isEmpty());
240: moveUpButton.setEnabled(!itemsToMoveUp().isEmpty());
241: moveDownButton.setEnabled(!itemsToMoveDown().isEmpty());
242: inputChangedFirer.fire();
243: }
244:
245: void addAllButton_actionPerformed(ActionEvent e) {
246: for (Iterator i = leftList.getModel().getItems().iterator(); i
247: .hasNext();) {
248: Object item = i.next();
249: rightList.getModel().add(item);
250: leftList.getModel().remove(item);
251: }
252:
253: updateEnabled();
254: }
255:
256: void removeAllButton_actionPerformed(ActionEvent e) {
257: for (Iterator i = rightList.getModel().getItems().iterator(); i
258: .hasNext();) {
259: Object item = i.next();
260: rightList.getModel().remove(item);
261: leftList.getModel().add(item);
262: }
263:
264: updateEnabled();
265: }
266:
267: void addButton_actionPerformed(ActionEvent e) {
268: addSelected();
269: }
270:
271: private void addSelected() {
272: for (Iterator i = leftList.getSelectedItems().iterator(); i
273: .hasNext();) {
274: Object selectedItem = i.next();
275: rightList.getModel().add(selectedItem);
276: leftList.getModel().remove(selectedItem);
277: }
278:
279: updateEnabled();
280: }
281:
282: void moveUpButton_actionPerformed(ActionEvent e) {
283: move(itemsToMoveUp(), -1);
284: }
285:
286: private void move(Collection itemsToMove, int displacement) {
287: Collection selectedItems = rightList.getSelectedItems();
288: List items = new ArrayList(rightList.getModel().getItems());
289:
290: for (Iterator i = itemsToMove.iterator(); i.hasNext();) {
291: Object item = i.next();
292: int index = items.indexOf(item);
293: items.remove(item);
294: items.add(index + displacement, item);
295: }
296:
297: rightList.getModel().setItems(items);
298: rightList.setSelectedItems(selectedItems);
299: updateEnabled();
300: }
301:
302: void moveDownButton_actionPerformed(ActionEvent e) {
303: move(itemsToMoveDown(), +1);
304: }
305:
306: private Collection itemsToMoveUp() {
307: return itemsToMoveUp(rightList.getModel().getItems(), rightList
308: .getSelectedItems());
309: }
310:
311: private Collection itemsToMoveDown() {
312: return itemsToMoveDown(rightList.getModel().getItems(),
313: rightList.getSelectedItems());
314: }
315:
316: public static Collection itemsToMoveDown(List items,
317: Collection selectedItems) {
318: List reverseItems = new ArrayList(items);
319: Collections.reverse(reverseItems);
320: return itemsToMoveUp(reverseItems, selectedItems);
321: }
322:
323: public static Collection itemsToMoveUp(List items,
324: Collection selectedItems) {
325: int firstUnselectedIndex = firstUnselectedIndex(items,
326: selectedItems);
327:
328: if (firstUnselectedIndex == -1) {
329: return new ArrayList();
330: }
331:
332: ArrayList itemsToMoveUp = new ArrayList();
333:
334: for (int i = firstUnselectedIndex; i < items.size(); i++) {
335: Object item = (Object) items.get(i);
336:
337: if (selectedItems.contains(item)) {
338: itemsToMoveUp.add(item);
339: }
340: }
341:
342: return itemsToMoveUp;
343: }
344:
345: private static int firstUnselectedIndex(List items,
346: Collection selectedItems) {
347: for (int i = 0; i < items.size(); i++) {
348: Object item = (Object) items.get(i);
349:
350: if (!selectedItems.contains(item)) {
351: return i;
352: }
353: }
354:
355: return -1;
356: }
357:
358: void removeButton_actionPerformed(ActionEvent e) {
359: removeSelected();
360: }
361:
362: private void removeSelected() {
363: for (Iterator i = rightList.getSelectedItems().iterator(); i
364: .hasNext();) {
365: Object selectedItem = i.next();
366: rightList.getModel().remove(selectedItem);
367: leftList.getModel().add(selectedItem);
368: }
369: updateEnabled();
370: }
371:
372: public void setLeftText(String newLeftText) {
373: if (leftLabel instanceof JLabel) {
374: ((JLabel) leftLabel).setText(newLeftText);
375: } else {
376: Assert.shouldNeverReachHere();
377: }
378: }
379:
380: public void setRightLabel(JComponent rightLabel) {
381: remove(rightLabel);
382: this .rightLabel = rightLabel;
383: add(rightLabel, new GridBagConstraints(34, 10, 1, 1, 0.0, 0.0,
384: GridBagConstraints.WEST, GridBagConstraints.BOTH,
385: new Insets(0, 0, 0, 0), 0, 0));
386: initLabelSizes();
387: }
388:
389: public void setLeftLabel(JComponent leftLabel) {
390: remove(leftLabel);
391: this .leftLabel = leftLabel;
392: add(leftLabel, new GridBagConstraints(12, 10, 2, 1, 0.0, 0.0,
393: GridBagConstraints.WEST, GridBagConstraints.BOTH,
394: new Insets(0, 0, 0, 0), 0, 0));
395: initLabelSizes();
396: }
397:
398: private void initLabelSizes() {
399: //Ensure left and right sides have same width [Jon Aquino]
400: Dimension d = new Dimension((int) Math.max(leftLabel
401: .getPreferredSize().getWidth(), rightLabel
402: .getPreferredSize().getWidth()), (int) Math.max(
403: leftLabel.getPreferredSize().getHeight(), rightLabel
404: .getPreferredSize().getHeight()));
405: leftLabel.setPreferredSize(d);
406: rightLabel.setPreferredSize(d);
407: }
408:
409: public void setRightList(AddRemoveList rightList) {
410: rightScrollPane.getViewport().remove(
411: (JComponent) this .rightList);
412: this .rightList = rightList;
413: rightScrollPane.getViewport().add((JComponent) rightList, null);
414: init(rightList, rightScrollPane);
415: rightList.add(new MouseAdapter() {
416: public void mouseClicked(MouseEvent e) {
417: if (e.getClickCount() == 2
418: && SwingUtilities.isLeftMouseButton(e)) {
419: removeSelected();
420: }
421: }
422: });
423: }
424:
425: private void init(AddRemoveList list, JScrollPane scrollPane) {
426: list.add(new InputChangedListener() {
427: public void inputChanged() {
428: updateEnabled();
429: }
430: });
431:
432: //A tip from Jason Ross to ensure that the left and right panels start
433: //the same size and stay that way when the dialog is resized: simply make
434: //sure their preferred sizes are initially the same. [Jon Aquino]
435: scrollPane.setPreferredSize(new Dimension(10, 10));
436: updateEnabled();
437: }
438:
439: public void setLeftList(AddRemoveList leftList) {
440: leftScrollPane.getViewport().remove((JComponent) this .leftList);
441: this .leftList = leftList;
442: leftScrollPane.getViewport().add((JComponent) leftList, null);
443: init(leftList, leftScrollPane);
444: leftList.add(new MouseAdapter() {
445: public void mouseClicked(MouseEvent e) {
446: if (e.getClickCount() == 2
447: && SwingUtilities.isLeftMouseButton(e)) {
448: addSelected();
449: }
450: }
451: });
452: }
453:
454: public void setRightText(String newRightText) {
455: if (rightLabel instanceof JLabel) {
456: ((JLabel) rightLabel).setText(newRightText);
457: } else {
458: Assert.shouldNeverReachHere();
459: }
460: }
461:
462: public List getLeftItems() {
463: return leftList.getModel().getItems();
464: }
465:
466: public List getRightItems() {
467: return rightList.getModel().getItems();
468: }
469:
470: public AddRemoveList getLeftList() {
471: return leftList;
472: }
473:
474: public AddRemoveList getRightList() {
475: return rightList;
476: }
477: }
|