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: package com.vividsolutions.jump.workbench.ui;
033:
034: import java.awt.BorderLayout;
035: import java.awt.Rectangle;
036: import java.awt.event.ActionEvent;
037: import java.awt.event.ActionListener;
038: import java.awt.event.MouseAdapter;
039: import java.awt.event.MouseEvent;
040: import java.awt.event.MouseListener;
041: import java.awt.geom.NoninvertibleTransformException;
042: import java.util.ArrayList;
043: import java.util.Arrays;
044: import java.util.Collection;
045:
046: import javax.swing.Icon;
047: import javax.swing.JButton;
048: import javax.swing.JComponent;
049: import javax.swing.JPanel;
050: import javax.swing.JScrollPane;
051: import javax.swing.JTable;
052: import javax.swing.JToolBar;
053: import javax.swing.SwingUtilities;
054: import javax.swing.event.ListSelectionEvent;
055: import javax.swing.event.ListSelectionListener;
056:
057: import org.openjump.sigle.plugin.replace.ReplaceValuePlugIn;
058:
059: import com.vividsolutions.jump.I18N;
060: import com.vividsolutions.jump.workbench.WorkbenchContext;
061: import com.vividsolutions.jump.workbench.model.CategoryEvent;
062: import com.vividsolutions.jump.workbench.model.FeatureEvent;
063: import com.vividsolutions.jump.workbench.model.Layer;
064: import com.vividsolutions.jump.workbench.model.LayerEvent;
065: import com.vividsolutions.jump.workbench.model.LayerEventType;
066: import com.vividsolutions.jump.workbench.model.LayerListener;
067: import com.vividsolutions.jump.workbench.model.LayerManager;
068: import com.vividsolutions.jump.workbench.model.LayerManagerProxy;
069: import com.vividsolutions.jump.workbench.model.Layerable;
070: import com.vividsolutions.jump.workbench.plugin.EnableCheck;
071: import com.vividsolutions.jump.workbench.plugin.MultiEnableCheck;
072: import com.vividsolutions.jump.workbench.plugin.PlugIn;
073: import com.vividsolutions.jump.workbench.plugin.PlugInContext;
074: import com.vividsolutions.jump.workbench.ui.cursortool.FeatureInfoTool;
075: import com.vividsolutions.jump.workbench.ui.images.IconLoader;
076: import com.vividsolutions.jump.workbench.ui.plugin.FeatureInfoPlugIn;
077: import com.vividsolutions.jump.workbench.ui.plugin.FeatureInstaller;
078:
079: /**
080: * Implements an Attribute Tab.
081: */
082:
083: public class AttributeTab extends JPanel implements LayerNamePanel {
084: private BorderLayout borderLayout1 = new BorderLayout();
085: private ErrorHandler errorHandler;
086: private TaskFrame taskFrame;
087: private LayerManagerProxy layerManagerProxy;
088:
089: //The String values returned by these EnableChecks are not used.
090: //The only thing checked is whether they are null or not. [Jon Aquino]
091: private EnableCheck taskFrameEnableCheck = new EnableCheck() {
092: public String check(JComponent component) {
093: return (!taskFrame.isVisible()) ? I18N
094: .get("ui.AttributeTab.task-frame-must-be-open")
095: : null;
096: }
097: };
098:
099: private EnableCheck layersEnableCheck = new EnableCheck() {
100: public String check(JComponent component) {
101: return panel.getModel().getLayers().isEmpty() ? I18N
102: .get("ui.AttributeTab.one-or-more-layers-must-be-present")
103: : null;
104: }
105: };
106:
107: private AttributePanel panel;
108: private JScrollPane scrollPane = new JScrollPane();
109: private EnableCheck rowsSelectedEnableCheck = new EnableCheck() {
110: public String check(JComponent component) {
111: return panel.selectedFeatures().isEmpty() ? I18N
112: .get("ui.AttributeTab.one-or-more-rows-must-be-selected")
113: : null;
114: }
115: };
116:
117: private EnableableToolBar toolBar = new EnableableToolBar();
118: private InfoModel model;
119: private Layer[] selectedLayers = new Layer[] {};
120: private Layer[] lastSelectedLayers = new Layer[] {};
121:
122: public InfoModel getModel() {
123: return model;
124: }
125:
126: public AttributeTab(final InfoModel model,
127: final WorkbenchContext workbenchContext,
128: final TaskFrame taskFrame,
129: LayerManagerProxy layerManagerProxy,
130: boolean addScrollPanesToChildren) {
131: this .layerManagerProxy = layerManagerProxy;
132: this .model = model;
133: this .taskFrame = taskFrame;
134: taskFrame.addInternalFrameListener(GUIUtil
135: .toInternalFrameListener(new ActionListener() {
136: public void actionPerformed(ActionEvent e) {
137: toolBar.updateEnabledState();
138: }
139: }));
140: panel = new AttributePanel(model, workbenchContext, taskFrame,
141: layerManagerProxy, addScrollPanesToChildren) {
142: public void layerAdded(LayerTableModel layerTableModel) {
143: super .layerAdded(layerTableModel);
144:
145: final AttributeTablePanel tablePanel = getTablePanel(layerTableModel
146: .getLayer());
147: MouseListener mouseListener = new MouseAdapter() {
148: public void mouseReleased(MouseEvent e) {
149: if (!SwingUtilities.isRightMouseButton(e)) {
150: return;
151: }
152:
153: popupMenu(workbenchContext).setTitle(
154: tablePanel.getModel().getLayer()
155: .getName());
156: lastSelectedLayers = new Layer[] { tablePanel
157: .getModel().getLayer() };
158:
159: //Call #setEnableLastSelectedLayers here for EnableChecks that
160: //call #getSelectedLayers. [Jon Aquino]
161: setEnableLastSelectedLayers(true,
162: AttributeTab.this );
163:
164: try {
165: popupMenu(workbenchContext).show(
166: tablePanel.getLayerNameRenderer(),
167: e.getX(), e.getY());
168: } finally {
169: setEnableLastSelectedLayers(false,
170: AttributeTab.this );
171: }
172: }
173: };
174:
175: tablePanel.addMouseListener(mouseListener);
176: tablePanel.getTable().addMouseListener(mouseListener);
177: tablePanel.getTable().getTableHeader()
178: .addMouseListener(mouseListener);
179: tablePanel.getLayerNameRenderer().addMouseListener(
180: mouseListener);
181: }
182: };
183: layerManagerProxy.getLayerManager().addLayerListener(
184: new LayerListener() {
185: public void featuresChanged(FeatureEvent e) {
186: }
187:
188: public void layerChanged(LayerEvent e) {
189: if (e.getType() == LayerEventType.METADATA_CHANGED) {
190: //Editability may have changed. [Jon Aquino]
191: toolBar.updateEnabledState();
192: }
193: }
194:
195: public void categoryChanged(CategoryEvent e) {
196: }
197: });
198: model.addListener(new InfoModelListener() {
199: public void layerAdded(LayerTableModel layerTableModel) {
200: panel.getTablePanel(layerTableModel.getLayer())
201: .getTable().getSelectionModel()
202: .addListSelectionListener(
203: new ListSelectionListener() {
204: public void valueChanged(
205: ListSelectionEvent e) {
206: toolBar.updateEnabledState();
207: }
208: });
209: toolBar.updateEnabledState();
210: }
211:
212: public void layerRemoved(LayerTableModel layerTableModel) {
213: toolBar.updateEnabledState();
214: }
215: });
216: this .errorHandler = workbenchContext.getErrorHandler();
217:
218: try {
219: jbInit();
220: } catch (Exception ex) {
221: ex.printStackTrace();
222: }
223:
224: initScrollPane();
225: if (addScrollPanesToChildren) {
226: remove(scrollPane);
227: add(panel, BorderLayout.CENTER);
228:
229: }
230: installToolBarButtons(workbenchContext, taskFrame);
231: toolBar.updateEnabledState();
232: }
233:
234: private void installToolBarButtons(
235: final WorkbenchContext workbenchContext,
236: final TaskFrame taskFrame) {
237: toolBar.add(new JButton(), I18N
238: .get("ui.AttributeTab.zoom-to-previous-row"),
239: IconLoader.icon("SmallUp.gif"), new ActionListener() {
240: public void actionPerformed(ActionEvent e) {
241: try {
242: zoom(panel.topSelectedRow().previousRow());
243: } catch (Throwable t) {
244: errorHandler.handleThrowable(t);
245: }
246: }
247: }, new MultiEnableCheck().add(taskFrameEnableCheck)
248: .add(layersEnableCheck));
249: toolBar.add(new JButton(), I18N
250: .get("ui.AttributeTab.zoom-to-next-row"), IconLoader
251: .icon("SmallDown.gif"), new ActionListener() {
252: public void actionPerformed(ActionEvent e) {
253: try {
254: zoom(panel.topSelectedRow().nextRow());
255: } catch (Throwable t) {
256: errorHandler.handleThrowable(t);
257: }
258: }
259: }, new MultiEnableCheck().add(taskFrameEnableCheck).add(
260: layersEnableCheck));
261: toolBar.add(new JButton(), I18N
262: .get("ui.AttributeTab.zoom-to-selected-rows"),
263: IconLoader.icon("SmallMagnify.gif"),
264: new ActionListener() {
265: public void actionPerformed(ActionEvent e) {
266: try {
267: panel.zoom(panel.selectedFeatures());
268: } catch (Throwable t) {
269: errorHandler.handleThrowable(t);
270: }
271: }
272: }, new MultiEnableCheck().add(taskFrameEnableCheck)
273: .add(layersEnableCheck).add(
274: rowsSelectedEnableCheck));
275: toolBar.add(new JButton(), I18N
276: .get("ui.AttributeTab.zoom-to-full-extent"), IconLoader
277: .icon("SmallWorld.gif"), new ActionListener() {
278: public void actionPerformed(ActionEvent e) {
279: try {
280: taskFrame.getLayerViewPanel().getViewport()
281: .zoomToFullExtent();
282: } catch (Throwable t) {
283: errorHandler.handleThrowable(t);
284: }
285: }
286: }, new MultiEnableCheck().add(taskFrameEnableCheck).add(
287: layersEnableCheck));
288: toolBar.add(new JButton(), I18N
289: .get("ui.AttributeTab.select-in-task-window"),
290: IconLoader.icon("SmallSelect.gif"),
291: new ActionListener() {
292: public void actionPerformed(ActionEvent e) {
293: try {
294: panel.selectInLayerViewPanel();
295: } catch (Throwable t) {
296: errorHandler.handleThrowable(t);
297: }
298: }
299: }, new MultiEnableCheck().add(taskFrameEnableCheck)
300: .add(layersEnableCheck).add(
301: rowsSelectedEnableCheck));
302: toolBar.add(new JButton(), I18N
303: .get("ui.AttributeTab.flash-selected-rows"), IconLoader
304: .icon("Flashlight.gif"), new ActionListener() {
305: public void actionPerformed(ActionEvent e) {
306: try {
307: panel.flashSelectedFeatures();
308: } catch (Throwable t) {
309: errorHandler.handleThrowable(t);
310: }
311: }
312: }, new MultiEnableCheck().add(taskFrameEnableCheck).add(
313: layersEnableCheck).add(rowsSelectedEnableCheck));
314:
315: FeatureInfoPlugIn featureInfoPlugIn = new FeatureInfoPlugIn();
316: toolBar.add(new JButton(), featureInfoPlugIn.getName(), GUIUtil
317: .toSmallIcon(FeatureInfoTool.ICON), FeatureInfoPlugIn
318: .toActionListener(featureInfoPlugIn, workbenchContext,
319: null), FeatureInfoPlugIn
320: .createEnableCheck(workbenchContext));
321:
322: //-- [sstein 4 nov 2006] added replace value
323: /* but is not yet activated since problems appear:
324: * either with enableCheck => nullpointer
325: * or with actionPerformed => update of window?
326: */
327: /**
328: ReplaceValuePlugIn myReplacePlugIn = new ReplaceValuePlugIn();
329: toolBar.add(
330: new JButton(),
331: myReplacePlugIn.getName(),
332: GUIUtil.toSmallIcon(ReplaceValuePlugIn.ICON),
333: ReplaceValuePlugIn.toActionListener(myReplacePlugIn, workbenchContext, null),
334: ReplaceValuePlugIn.createEnableCheck(workbenchContext));
335: **/
336: }
337:
338: public TaskFrame getTaskFrame() {
339: return taskFrame;
340: }
341:
342: public Layer chooseEditableLayer() {
343: return TreeLayerNamePanel.chooseEditableLayer(this );
344: }
345:
346: public LayerManager getLayerManager() {
347: return layerManagerProxy.getLayerManager();
348: }
349:
350: void jbInit() throws Exception {
351: this .setLayout(borderLayout1);
352: toolBar.setOrientation(JToolBar.VERTICAL);
353: scrollPane.getViewport().add(panel, null);
354: this .add(scrollPane, BorderLayout.CENTER);
355: this .add(toolBar, BorderLayout.WEST);
356: }
357:
358: private void initScrollPane() {
359: scrollPane.getVerticalScrollBar().setUnitIncrement(
360: new JTable().getRowHeight());
361: }
362:
363: private void zoom(AttributePanel.Row row)
364: throws NoninvertibleTransformException {
365: panel.clearSelection();
366: //fixed : if the layer don't have any feature, do nothing.
367: if (row.getPanel().getTable().getModel().getRowCount() == 0) {
368: return;
369: }
370: row.getPanel().getTable().getSelectionModel()
371: .setSelectionInterval(row.getIndex(), row.getIndex());
372:
373: Rectangle r = row.getPanel().getTable().getCellRect(
374: row.getIndex(), 0, true);
375: row.getPanel().getTable().scrollRectToVisible(r);
376:
377: if (row.isFirstRow()) {
378: //Make header visible [Jon Aquino]
379: row.getPanel().scrollRectToVisible(
380: new Rectangle(0, 0, 1, 1));
381: }
382:
383: ArrayList features = new ArrayList();
384: features.add(row.getFeature());
385: panel.zoom(features);
386: }
387:
388: public static TitledPopupMenu popupMenu(WorkbenchContext context) {
389: return (TitledPopupMenu) context.getWorkbench().getBlackboard()
390: .get(
391: AttributeTab.class.getName()
392: + " - LAYER POPUP MENU",
393: new TitledPopupMenu());
394: }
395:
396: public static void addPopupMenuItem(
397: WorkbenchContext workbenchContext, PlugIn plugIn,
398: String menuItemName, boolean checkBox, Icon icon,
399: EnableCheck enableCheck) {
400: new FeatureInstaller(workbenchContext).addPopupMenuItem(
401: popupMenu(workbenchContext), wrap(plugIn),
402: menuItemName, checkBox, icon, enableCheck);
403: }
404:
405: private static PlugIn wrap(final PlugIn plugIn) {
406: //Can't simply add an ActionListener to the menu item to determine when the
407: //plug-in finishes because ActionListeners are notified last to first (see
408: //AbstractButton#fireActionPerformed). [Jon Aquino]
409: return new PlugIn() {
410: public void initialize(PlugInContext context)
411: throws Exception {
412: plugIn.initialize(context);
413: }
414:
415: public boolean execute(PlugInContext context)
416: throws Exception {
417: //Save attributeTab before executing plug-in, as it may change active window. [Jon Aquino]
418: AttributeTab attributeTab = (AttributeTab) context
419: .getLayerNamePanel();
420: setEnableLastSelectedLayers(true, attributeTab);
421:
422: try {
423: return plugIn.execute(context);
424: } finally {
425: setEnableLastSelectedLayers(false, attributeTab);
426: }
427: }
428:
429: public String getName() {
430: return plugIn.getName();
431: }
432: };
433: }
434:
435: private static void setEnableLastSelectedLayers(boolean enabled,
436: AttributeTab attributeTab) {
437: attributeTab.selectedLayers = enabled ? attributeTab.lastSelectedLayers
438: : new Layer[] {};
439: }
440:
441: public Collection getSelectedCategories() {
442: return new ArrayList();
443: }
444:
445: public Layer[] getSelectedLayers() {
446: if (model.getLayers().size() == 1) {
447: return new Layer[] { (Layer) model.getLayers().get(0) };
448: }
449:
450: return selectedLayers;
451: }
452:
453: public Collection selectedNodes(Class c) {
454: if (!Layerable.class.isAssignableFrom(c)) {
455: return new ArrayList();
456: }
457:
458: return Arrays.asList(getSelectedLayers());
459: }
460:
461: public AttributePanel getPanel() {
462: return panel;
463: }
464:
465: public EnableableToolBar getToolBar() {
466: return toolBar;
467: }
468:
469: public void addListener(LayerNamePanelListener listener) {
470: }
471:
472: public void removeListener(LayerNamePanelListener listener) {
473: }
474:
475: public void dispose() {
476: }
477:
478: }
|