Package org.locationtech.udig.tools.internal

Source Code of org.locationtech.udig.tools.internal.PanTool

/*
*    uDig - User Friendly Desktop Internet GIS client
*    http://udig.refractions.net
*    (C) 2004, Refractions Research Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD
* License v1.0 (http://udig.refractions.net/files/bsd3-v10.html).
*
*/
package org.locationtech.udig.tools.internal;

import java.awt.Point;

import org.locationtech.udig.project.IMap;
import org.locationtech.udig.project.command.Command;
import org.locationtech.udig.project.command.NavCommand;
import org.locationtech.udig.project.internal.Map;
import org.locationtech.udig.project.internal.command.navigation.AbstractNavCommand;
import org.locationtech.udig.project.internal.command.navigation.PanCommand;
import org.locationtech.udig.project.internal.render.ViewportModel;
import org.locationtech.udig.project.internal.render.impl.ViewportModelImpl;
import org.locationtech.udig.project.ui.internal.commands.draw.TranslateCommand;
import org.locationtech.udig.project.ui.render.displayAdapter.MapMouseEvent;
import org.locationtech.udig.project.ui.render.displayAdapter.ViewportPane;
import org.locationtech.udig.project.ui.tool.AbstractModalTool;
import org.locationtech.udig.project.ui.tool.ModalTool;
import org.locationtech.udig.project.ui.tool.options.ToolOptionContributionItem;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.geotools.geometry.jts.ReferencedEnvelope;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;

/**
* Provides Pan functionality for MapViewport; the technique used for panning is controlled via
* preferences.
* <p>
* There are three strateies avaialble {@link Pan}, {@link Scroll}, {@link FixedScale}.
*
* @author Jesse Eichar
* @version $Revision: 1.9 $
*/
public class PanTool extends AbstractModalTool implements ModalTool {
    public static class OptionContribtionItem extends ToolOptionContributionItem {
        public IPreferenceStore fillFields( Composite parent ) {
            Button check = new Button(parent,  SWT.CHECK );
            check.setText("Scale");
            addField( NavigationToolPreferencePage.SCALE, check );
        
            Button tiled = new Button(parent,  SWT.CHECK );
            tiled.setText("Tiled");
            addField( NavigationToolPreferencePage.TILED, tiled );
           
            return ToolsPlugin.getDefault().getPreferenceStore();
        }
    };
    /**
     * Delegate used to control how the PanTool functions; configured using Preference.
     * @author Jody Garnett (LISAsoft)
     * @since 1.2.0
     */
    abstract class ScrollStrategy {
        public void mouseDragged( MapMouseEvent e ) {
        }
        public void mousePressed( MapMouseEvent e ) {
        }
        public void mouseReleased( MapMouseEvent e ) {
        }
        public void dispose() {
        }
    };
    private ScrollStrategy strategy;
    IPropertyChangeListener prefListener = new IPropertyChangeListener(){
        public void propertyChange( PropertyChangeEvent event ) {
            String property = event.getProperty();
            if( NavigationToolPreferencePage.SCALE.equals( property ) ||
                    NavigationToolPreferencePage.TILED.equals( property ) ){
                syncStrategy();
            }
        }
    };
    /**
     * Creates an new instance of Pan
     */
    public PanTool() {
        super(MOUSE | MOTION);
        IPreferenceStore preferenceStore = ToolsPlugin.getDefault().getPreferenceStore();
        preferenceStore.addPropertyChangeListener(prefListener);
        syncStrategy();
    }
    public void syncStrategy(){
        IPreferenceStore preferenceStore = ToolsPlugin.getDefault().getPreferenceStore();
        boolean scale = preferenceStore.getBoolean(NavigationToolPreferencePage.SCALE);
        boolean tiled = preferenceStore.getBoolean(NavigationToolPreferencePage.TILED);
        if (scale) {
            strategy = new FixedScale();
        }
        else if (tiled){
            strategy = new Scroll();
        }
        else {
            strategy = new Pan();
        }
       
    }
    /**
     * Used to recognise a mouse event and pan accodingly.
     * <p>
     * This functionality is overridden by PanMiddleMouse in order to allow the middle mouse button
     * to provide the Pan functionality for any ModalTool.
     *
     * @param e
     */
    protected boolean validModifierButtonCombo( MapMouseEvent e ) {
        return e.buttons == MapMouseEvent.BUTTON1 && !(e.modifiersDown());
    }
    /**
     * @see org.locationtech.udig.project.ui.tool.AbstractTool#mouseDragged(org.locationtech.udig.project.render.displayAdapter.MapMouseEvent)
     */
    public void mouseDragged( MapMouseEvent e ) {
        strategy.mouseDragged(e);
    }

    /**
     * @see org.locationtech.udig.project.ui.tool.AbstractTool#mousePressed(org.locationtech.udig.project.render.displayAdapter.MapMouseEvent)
     */
    public void mousePressed( MapMouseEvent e ) {
        strategy.mousePressed(e);
    }

    /**
     * @see org.locationtech.udig.project.ui.tool.AbstractTool#mouseReleased(org.locationtech.udig.project.render.displayAdapter.MapMouseEvent)
     */
    public void mouseReleased( MapMouseEvent e ) {
        strategy.mouseReleased(e);
    }
    /**
     * @see org.locationtech.udig.project.ui.tool.Tool#dispose()
     */
    public void dispose() {
        if (strategy != null) {
            strategy.dispose();
            strategy = null;
        }
        super.dispose();
    }

    /**
     * Executes the specified pan command, and only after it is executed, expires the last translate
     * command
     */
    private class PanAndInvalidate implements Command, NavCommand {
        private NavCommand command;
        private TranslateCommand expire;
        PanAndInvalidate( NavCommand command, TranslateCommand expire ) {
            this.command = command;
            this.expire = expire;
        }

        public Command copy() {
            return new PanAndInvalidate(command, expire);
        }

        public String getName() {
            return "PanAndDiscard";
        }

        public void run( IProgressMonitor monitor ) throws Exception {
            // we need to expire the translate command first otherwise
            // the image gets drawn in the wrong spot the first time
            // and we see weird affects
            expire.setValid(false);

            command.run(monitor);
        }

        public void setViewportModel( ViewportModel model ) {
            command.setViewportModel(model);
        }

        public Map getMap() {
            return command.getMap();
        }

        public void setMap( IMap map ) {
            command.setMap(map);
        }

        public void rollback( IProgressMonitor monitor ) throws Exception {
            command.rollback(monitor);
        }
    }

    /** Basic Pan Functionality for MapViewport */
    public class Pan extends ScrollStrategy {
        private boolean dragging = false;
        private Point start = null;
        private TranslateCommand command;
        public void mouseDragged( MapMouseEvent e ) {
            if (dragging) {
                command.setTranslation(e.x - start.x, e.y - start.y);
                context.getViewportPane().repaint();
            }
        }

        /**
         * @see org.locationtech.udig.project.ui.tool.AbstractTool#mousePressed(org.locationtech.udig.project.render.displayAdapter.MapMouseEvent)
         */
        public void mousePressed( MapMouseEvent e ) {
            if (validModifierButtonCombo(e)) {
                ((ViewportPane) context.getMapDisplay()).enableDrawCommands(false);
                dragging = true;
                start = e.getPoint();
                command = context.getDrawFactory().createTranslateCommand(0, 0);
                context.sendASyncCommand(command);
            }
        }

        /**
         * @see org.locationtech.udig.project.ui.tool.AbstractTool#mouseReleased(org.locationtech.udig.project.render.displayAdapter.MapMouseEvent)
         */
        public void mouseReleased( MapMouseEvent e ) {
            if (dragging) {
                ((ViewportPane) context.getMapDisplay()).enableDrawCommands(true);
                Point end = e.getPoint();
                NavCommand finalPan = new PanCommand((start.x - end.x), (start.y - end.y));

                // clear any events before we try to pan. This dramatically reduces the number
                // of images drawn to the screen in the wrong spot
                ((ViewportPane) getContext().getMapDisplay()).update();

                context.sendASyncCommand(new PanAndInvalidate(finalPan, command));
                dragging = false;
            }
        }
    }
    /**
     * This strategy is used for tiled rendering; it pans without using complex Transforms. It pans
     * using the scroll functionality provided by canvas. This can produce a smoother panning
     * experience.
     * <p>
     * It also allows for rendering systems to notice when panning is occurring and update the image
     * as necessary.
     * </p>
     * <p>
     * If you are using the tile rendering system, this tool will allow for tiles to be loaded while
     * panning.
     * </p>
     * <p>
     * Currently, this tool will not produce an improved panning experience for the default udig
     * rendering system as it this system uses advanced graphics and does not pay attention to the
     * IsBoundsChanging attribute of the viewport model. However it could be updated to pay
     * attention to this attribute.
     * </p>
     */
    class Scroll extends ScrollStrategy {
        private boolean dragging = false;
        private org.eclipse.swt.graphics.Point start = null;
        /**
         * @see org.locationtech.udig.project.ui.tool.AbstractTool#mouseDragged(org.locationtech.udig.project.render.displayAdapter.MapMouseEvent)
         */
        public void mouseDragged( MapMouseEvent e ) {
            if (dragging) {
                org.eclipse.swt.graphics.Point p = Display.getCurrent().map(
                        (Canvas) context.getViewportPane(), null, e.x, e.y);
                int xdiff = p.x - start.x;
                int ydiff = p.y - start.y;

                final ReferencedEnvelope bounds = context.getViewportModel().getBounds();
                Coordinate oldc = context.pixelToWorld(start.x, start.y);
                Coordinate newc = context.pixelToWorld(p.x, p.y);
                double xoffset = newc.x - oldc.x;
                double yoffset = newc.y - oldc.y;

                ReferencedEnvelope newbounds = new ReferencedEnvelope(bounds.getMinX() - xoffset,
                        bounds.getMaxX() - xoffset, bounds.getMinY() - yoffset, bounds.getMaxY()
                                - yoffset, bounds.getCoordinateReferenceSystem());

                ((Canvas) context.getViewportPane()).scroll(xdiff, ydiff, 0, 0, context
                        .getMapDisplay().getWidth(), context.getMapDisplay().getHeight(), true);
                ((ViewportModel) context.getViewportModel()).setBounds(newbounds);
                start = p;
            }
        }

        /**
         * @see org.locationtech.udig.project.ui.tool.AbstractTool#mousePressed(org.locationtech.udig.project.render.displayAdapter.MapMouseEvent)
         */
        public void mousePressed( MapMouseEvent e ) {
            if (validModifierButtonCombo(e)) {
                ((ViewportPane) context.getMapDisplay()).enableDrawCommands(false);
                ((ViewportModel) context.getViewportModel()).setIsBoundsChanging(true);
                dragging = true;
                start = Display.getCurrent()
                        .map((Canvas) context.getViewportPane(), null, e.x, e.y);
            }
        }
        public void mouseReleased( MapMouseEvent e ) {
            if (dragging) {

                ((ViewportModel) context.getViewportModel()).setIsBoundsChanging(false);
                ((ViewportPane) context.getMapDisplay()).enableDrawCommands(true);

                dragging = false;

                org.eclipse.swt.graphics.Point p = Display.getCurrent().map(
                        (Canvas) context.getViewportPane(), null, e.x, e.y);
                int xdiff = p.x - start.x;
                int ydiff = p.y - start.y;

                ReferencedEnvelope bounds = context.getViewportModel().getBounds();
                Coordinate oldc = context.pixelToWorld(start.x, start.y);
                Coordinate newc = context.pixelToWorld(p.x, p.y);
                double xoffset = newc.x - oldc.x;
                double yoffset = newc.y - oldc.y;

                ReferencedEnvelope newbounds = new ReferencedEnvelope(bounds.getMinX() - xoffset,
                        bounds.getMaxX() - xoffset, bounds.getMinY() - yoffset, bounds.getMaxY()
                                - yoffset, bounds.getCoordinateReferenceSystem());

                ((Canvas) context.getViewportPane()).scroll(xdiff, ydiff, 0, 0, context
                        .getMapDisplay().getWidth(), context.getMapDisplay().getHeight(), true);
                start = p;

                // do one last set bounds that fires all the events to ensure our update is correct
                ((ViewportModelImpl) context.getViewportModel()).setBounds(newbounds);
            }
        }
        public void dispose() {
            super.dispose();
        }
    }
    /**
     * This tool is supposed to be a fixed scale zoom tool.
     * <p>
     * Internally this strategy uses a "TranslateCommand" to give visual feedback during the mouse
     * drag. When the mouse is released the screen is redrawn as needed.
     * <p>
     * What makes this interesting is the "Fixed" scale aspect; this means that the screen may
     * change resolution as the MapViewport tries to maintain the current scale (as you move north
     * and south). Emily reports that the strategy does not actually do this properly.
     * </p>
     *
     * @author Emily Gouge
     * @since 1.2.0
     */
    class FixedScale extends ScrollStrategy {
        private boolean dragging = false;
        private Point start = null;
        private ReferencedEnvelope startbounds = null;

        TranslateCommand command;

        /**
         * @see org.locationtech.udig.project.ui.tool.AbstractTool#mouseDragged(org.locationtech.udig.project.render.displayAdapter.MapMouseEvent)
         */
        public void mouseDragged( MapMouseEvent e ) {
            if (dragging) {
                command.setTranslation(e.x - start.x, e.y - start.y);
                context.getViewportPane().repaint();
            }
        }

        /**
         * @see org.locationtech.udig.project.ui.tool.AbstractTool#mousePressed(org.locationtech.udig.project.render.displayAdapter.MapMouseEvent)
         */
        public void mousePressed( MapMouseEvent e ) {

            if (validModifierButtonCombo(e)) {
                ((ViewportPane) context.getMapDisplay()).enableDrawCommands(false);
                dragging = true;
                start = e.getPoint();
                startbounds = new ReferencedEnvelope(context.getViewportModel().getBounds());
                command = context.getDrawFactory().createTranslateCommand(0, 0);
                context.sendASyncCommand(command);
            }
        }
        /**
         * @see org.locationtech.udig.project.ui.tool.AbstractTool#mouseReleased(org.locationtech.udig.project.render.displayAdapter.MapMouseEvent)
         */
        public void mouseReleased( MapMouseEvent e ) {
            if (dragging) {

                ((ViewportPane) context.getMapDisplay()).enableDrawCommands(true);

                // update translation
                command.setTranslation(e.x - start.x, e.y - start.y);
                context.getViewportPane().repaint();

                // compute new offset
                Point end = e.getPoint();

                int deltax = (end.x - start.x);
                double deltaxworld = (getContext().getViewportModel().getWidth() / getContext()
                        .getMapDisplay().getWidth()) * deltax;

                int deltay = end.y - start.y;
                double deltayworld = (getContext().getViewportModel().getHeight() / getContext()
                        .getMapDisplay().getHeight()) * deltay;

                Coordinate center = startbounds.centre();
                final Coordinate newc = new Coordinate(center.x - deltaxworld, center.y
                        + deltayworld);

                double dw = getContext().getViewportModel().getBounds().getWidth() / 2;
                double dh = getContext().getViewportModel().getBounds().getHeight() / 2;

                final Envelope newbounds = new Envelope(newc.x - dw, newc.x + dw, newc.y - dh,
                        newc.y + dh);

                // double currentscale = context.getViewportModel().getBounds().getWidth() /
                // context.getMapDisplay().getWidth();
                // double newscale = newbounds.getWidth() / context.getMapDisplay().getWidth();

                // if (currentscale != newscale){
                // System.out.println("scale changed; should reload." );
                // System.out.println("current scale:" + currentscale);
                // System.out.println("aaaanew scale:" + newscale);
                // }

                // compute new bbox for
                NavCommand setFinal = new AbstractNavCommand(){

                    @Override
                    protected void runImpl( IProgressMonitor monitor ) throws Exception {
                        model.setBounds(newbounds);
                    }

                    public Command copy() {
                        return null;
                    }

                    public String getName() {
                        return "Fixed Scale Pan"; //$NON-NLS-1$
                    }
                };

                ((ViewportPane) getContext().getMapDisplay()).update();
                context.sendASyncCommand(new PanAndInvalidate(setFinal, command));

                dragging = false;
                // System.out.println("pan done.");
            }
        }
        /**
         * @see org.locationtech.udig.project.ui.tool.Tool#dispose()
         */
        public void dispose() {
            super.dispose();
        }

    }
}
TOP

Related Classes of org.locationtech.udig.tools.internal.PanTool

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.