/*
* The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
* for visualizing and manipulating spatial features with geometry and attributes.
*
* JUMP is Copyright (C) 2003 Vivid Solutions
*
* This program implements extensions to JUMP and is
* Copyright (C) Michaël Michaud.
*
* 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.
*
*/
package org.openjump.core.ui.plugin.window;
import org.openjump.core.ui.plugin.AbstractUiPlugIn;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jump.I18N;
import com.vividsolutions.jump.workbench.WorkbenchContext;
import com.vividsolutions.jump.workbench.plugin.EnableCheck;
import com.vividsolutions.jump.workbench.plugin.EnableCheckFactory;
import com.vividsolutions.jump.workbench.plugin.MultiEnableCheck;
import com.vividsolutions.jump.workbench.plugin.PlugInContext;
import com.vividsolutions.jump.workbench.ui.MenuNames;
import com.vividsolutions.jump.workbench.ui.TaskFrame;
import com.vividsolutions.jump.workbench.ui.Viewport;
import com.vividsolutions.jump.workbench.ui.ViewportListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import javax.swing.ButtonGroup;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JInternalFrame;
/**
* A plugin to synchronize / desynchronize LayerViewPanels.
*
* @author Michael Michaud
* @version 0.1 (2008-04-06)
* @since 1.2F
*/
public class SynchronizationPlugIn extends AbstractUiPlugIn {
static ViewportListener vpl;
public SynchronizationPlugIn(String name) {
super(name);
}
public void initialize(final PlugInContext context) throws Exception {
// Set the workbenchContext used in getEnableCheck method
super.initialize(context);
final JRadioButtonMenuItem desynchronizeMI =
new JRadioButtonMenuItem(I18N.get("org.openjump.core.ui.plugin.window.SyncronizationPlugIn.Desynchronize"));
final JRadioButtonMenuItem synchronizePanMI =
new JRadioButtonMenuItem(I18N.get("org.openjump.core.ui.plugin.window.SyncronizationPlugIn.Synchronize-pan-only"));
final JRadioButtonMenuItem synchronizeAllMI =
new JRadioButtonMenuItem(I18N.get("org.openjump.core.ui.plugin.window.SyncronizationPlugIn.Synchronize-pan-and-zoom"));
ButtonGroup bgroup = new ButtonGroup();
bgroup.add(desynchronizeMI);
bgroup.add(synchronizePanMI);
bgroup.add(synchronizeAllMI);
desynchronizeMI.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {desynchronize();}
});
synchronizePanMI.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {synchronize(false);}
});
synchronizeAllMI.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {synchronize(true);}
});
context.getFeatureInstaller().addMainMenuItem(
new String[]{MenuNames.WINDOW, MenuNames.WINDOW_SYNCHRONIZATION},
this,
synchronizePanMI,
0);
context.getFeatureInstaller().addMainMenuItem(
new String[]{MenuNames.WINDOW, MenuNames.WINDOW_SYNCHRONIZATION},
this,
synchronizeAllMI,
1);
context.getFeatureInstaller().addMainMenuItem(
new String[]{MenuNames.WINDOW, MenuNames.WINDOW_SYNCHRONIZATION},
this,
desynchronizeMI,
2);
}
public String getName() {
return I18N.get("org.openjump.core.ui.plugin.window.SyncronizationPlugIn.Synchronization");
}
public EnableCheck getEnableCheck() {
EnableCheckFactory checkFactory = new EnableCheckFactory(workbenchContext);
return new MultiEnableCheck()
.add(checkFactory.createWindowWithLayerViewPanelMustBeActiveCheck());
}
public void synchronize(boolean panAndZoom) {
ViewportListener oldViewportListener = vpl;
vpl = createViewportListener(panAndZoom);
// add the listener to every active map window
JInternalFrame[] iframes = workbenchContext.getWorkbench().getFrame().getInternalFrames();
for (JInternalFrame iframe : iframes) {
if (iframe instanceof TaskFrame) {
// Remove the old listener if any before adding a new one
// Thus, one can reinitialize synchronization if the number
// of map windows change
// Ideally, one should intercept new window creation or window focus
// change to add new listeners to new windows..
((TaskFrame)iframe).getLayerViewPanel().getViewport().removeListener(oldViewportListener);
((TaskFrame)iframe).getLayerViewPanel().getViewport().addListener(vpl);
}
}
}
public void desynchronize() {
ViewportListener oldViewPortListener = vpl;
vpl = null;
// add the listener to every active map window
JInternalFrame[] iframes = workbenchContext.getWorkbench().getFrame().getInternalFrames();
for (JInternalFrame iframe : iframes) {
if (iframe instanceof TaskFrame) {
// Remove the old listener if any before adding a new one
// Thus, one can reinitialize synchronization if the number
// of map windows change
// Ideally, one should intercept new window creation or window focus
// change to add new listeners to new windows..
((TaskFrame)iframe).getLayerViewPanel().getViewport().removeListener(oldViewPortListener);
}
}
}
private ViewportListener createViewportListener(final boolean panAndZoom) {
final WorkbenchContext context = workbenchContext;
return new ViewportListener() {
public void zoomChanged(Envelope modelEnvelope) {
JInternalFrame[] iframes = context.getWorkbench().getFrame().getInternalFrames();
for (JInternalFrame iframe : iframes) {
if (iframe instanceof TaskFrame &&
((TaskFrame)iframe).getLayerViewPanel().getViewport() !=
context.getLayerViewPanel().getViewport()) {
try {
// Copy of method viewport.zoom(envelope)
// without the statement fireZoomChanged(modelEnvelope)
// to avoid entering an infinite loop
// window 1 change --> window 2 change --> window 1 change ...
Viewport viewport = ((TaskFrame)iframe).getLayerViewPanel().getViewport();
double w = viewport.getPanel().getWidth();
double h = viewport.getPanel().getHeight();
double scale = viewport.getScale();
if (panAndZoom) {
scale = Math.min(w / modelEnvelope.getWidth(),
h / modelEnvelope.getHeight());
}
double xCenteringOffset = ((w / scale) - modelEnvelope.getWidth()) / 2.0;
double yCenteringOffset = ((h / scale) - modelEnvelope.getHeight()) / 2.0;
Point2D.Double viewOriginAsPerceivedByModel =
new Point2D.Double(modelEnvelope.getMinX() - xCenteringOffset,
modelEnvelope.getMinY() - yCenteringOffset);
viewport.initialize(scale, viewOriginAsPerceivedByModel);
viewport.update();
} catch(Exception e) {}
}
}
}
};
}
/**
* For this plugin, this method is unused
* All the work is defined in action listeners
*/
public boolean execute(PlugInContext context) throws Exception{
return true;
}
}