net.refractions.udig.catalog.internal.wmt.ui.view.WMTZoomLevelSwitcher.java Source code

Java tutorial

Introduction

Here is the source code for net.refractions.udig.catalog.internal.wmt.ui.view.WMTZoomLevelSwitcher.java

Source

/* uDig - User Friendly Desktop Internet GIS client
 * http://udig.refractions.net
 * (C) 2010, Refractions Research Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License.
 *
 * This library 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
 * Lesser General Public License for more details.
 */
package net.refractions.udig.catalog.internal.wmt.ui.view;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import net.refractions.udig.catalog.IGeoResource;
import net.refractions.udig.catalog.internal.wmt.WMTPlugin;
import net.refractions.udig.catalog.internal.wmt.WMTRenderJob;
import net.refractions.udig.catalog.internal.wmt.WMTScaleZoomLevelMatcher;
import net.refractions.udig.catalog.internal.wmt.wmtsource.WMTSource;
import net.refractions.udig.catalog.wmt.internal.Messages;
import net.refractions.udig.project.ILayer;
import net.refractions.udig.project.IMap;
import net.refractions.udig.project.IMapCompositionListener;
import net.refractions.udig.project.MapCompositionEvent;
import net.refractions.udig.project.internal.Map;
import net.refractions.udig.project.internal.commands.SetScaleCommand;
import net.refractions.udig.project.render.IViewportModelListener;
import net.refractions.udig.project.render.ViewportModelEvent;
import net.refractions.udig.project.ui.ApplicationGIS;

import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.part.ViewPart;
import org.geotools.geometry.jts.ReferencedEnvelope;

public class WMTZoomLevelSwitcher extends ViewPart {

    // Listeners
    private ISelectionChangedListener listenerZoomLevel;
    private IMapCompositionListener listenerMap;
    private IViewportModelListener listenerViewport;
    private IPartListener listenerMapEditor;

    // GUI elements
    private Composite parentControl;

    private Button btnZoomOut;
    private Button btnZoomIn;

    private ComboViewer cvLayers;
    private ComboViewer cvZoomLevels;

    // Map/Layers/Zoom-Levels
    private IMap currentMap = ApplicationGIS.NO_MAP;
    private List<ILayer> layerList;

    private Integer[] zoomLevels;

    // Icons
    private ImageRegistry imageCache;
    private static final String ICONS_PATH = "/icons/etool16/"; //$NON-NLS-1$
    private static final String ICON_ZOOM_IN = "ZOOM_IN"; //$NON-NLS-1$
    private static final String ICON_ZOOM_IN_PATH = ICONS_PATH + "zoom_in_co.gif"; //$NON-NLS-1$
    private static final String ICON_ZOOM_OUT = "ZOOM_OUT"; //$NON-NLS-1$
    private static final String ICON_ZOOM_OUT_PATH = ICONS_PATH + "zoom_out_co.gif"; //$NON-NLS-1$

    public WMTZoomLevelSwitcher() {
        super();

        initListeners();
    }

    //region Init Listeners
    private void initListeners() {
        initMapListener();

        initViewportListener();

        initMapEditorListener();
    }

    private void initMapListener() {
        listenerMap = new IMapCompositionListener() {
            public void changed(MapCompositionEvent event) {

                if (parentControl == null || parentControl.isDisposed())
                    return;

                parentControl.getDisplay().asyncExec(new Runnable() {
                    public void run() {
                        updateGUI(ApplicationGIS.getActiveMap());
                    }
                });
            }
        };
    }

    private void initViewportListener() {
        listenerViewport = new IViewportModelListener() {
            public void changed(ViewportModelEvent event) {

                if (parentControl == null || parentControl.isDisposed())
                    return;

                // when the scale changes, update the zoom-level ComboBox  
                parentControl.getDisplay().asyncExec(new Runnable() {
                    public void run() {
                        updateGUIFromScale();
                    }
                });
            }
        };
    }

    private void initMapEditorListener() {
        listenerMapEditor = new IPartListener() {
            private IWorkbenchPart currentPart;

            public void partActivated(IWorkbenchPart part) {
                if (part == currentPart)
                    return;

                final IMap map = getMapFromPart(part);

                if (map != null) {
                    currentPart = part;

                    if (parentControl == null || parentControl.isDisposed())
                        return;

                    parentControl.getDisplay().asyncExec(new Runnable() {
                        public void run() {
                            setUpMapListeners(map);
                        }
                    });
                }

            }

            public void partBroughtToTop(IWorkbenchPart part) {
                partActivated(part);
            }

            public void partClosed(IWorkbenchPart part) {
                if (part == WMTZoomLevelSwitcher.this) {
                    if (parentControl == null || parentControl.isDisposed())
                        return;

                    // if the tool itself is closed
                    parentControl.getDisplay().asyncExec(new Runnable() {
                        public void run() {
                            removeAllListeners();

                            currentPart = null;
                        }
                    });

                    return;
                }

                if (part != currentPart)
                    return;

                final IMap map = getMapFromPart(part);

                if (map != null) {
                    if (parentControl == null || parentControl.isDisposed())
                        return;

                    // remove 
                    parentControl.getDisplay().asyncExec(new Runnable() {
                        public void run() {
                            removeMapListeners(map, true);
                        }
                    });
                }

                currentPart = null;
            }

            private IMap getMapFromPart(IWorkbenchPart part) {
                if (part != null) {
                    IAdaptable adaptable = (IAdaptable) part;
                    Object obj = adaptable.getAdapter(Map.class);

                    if (obj instanceof Map) {

                        return (Map) obj;
                    }
                }

                return null;
            }

            public void partDeactivated(IWorkbenchPart part) {
            }

            public void partOpened(IWorkbenchPart part) {
            }

        };
    }
    //endregion

    //region Add/remove listeners
    public void setUpMapListeners(IMap map) {
        // remove listeners from old map
        removeMapListeners(currentMap, false);

        // assure that the listeners are only once in the list of the new map
        removeMapListeners(map, false);

        map.addMapCompositionListener(listenerMap);
        map.getViewportModel().addViewportModelListener(listenerViewport);

        updateGUI(map);
    }

    public void removeMapListeners(IMap map, boolean updateGUI) {
        if (map == null || map == ApplicationGIS.NO_MAP)
            return;

        map.removeMapCompositionListener(listenerMap);
        map.getViewportModel().removeViewportModelListener(listenerViewport);

        if (updateGUI && parentControl != null && !parentControl.isDisposed()) {
            currentMap = ApplicationGIS.NO_MAP;
            layerList.clear();

            enableComponents(false);
        }
    }

    public void removeAllListeners() {
        removeMapListeners(currentMap, false);

        getSite().getWorkbenchWindow().getPartService().removePartListener(listenerMapEditor);
    }
    //endregion

    //region Create Control
    @Override
    public void createPartControl(final Composite parent) {
        parentControl = parent;

        Composite composite = new Composite(parent, SWT.NONE);
        composite.setLayout(new RowLayout(SWT.HORIZONTAL));

        //region Label "Layer"
        Label lblLayer = new Label(composite, SWT.HORIZONTAL);
        lblLayer.setText(Messages.ZoomLevelSwitcher_Layer);
        //endregion

        //region Layer ComboBox
        cvLayers = new ComboViewer(composite, SWT.READ_ONLY);

        cvLayers.setContentProvider(new ArrayContentProvider());
        cvLayers.setLabelProvider(new LabelProvider() {
            @Override
            public String getText(Object element) {
                if (element instanceof ILayer) {
                    return ((ILayer) element).getName();
                } else {
                    return super.getText(element);
                }
            }
        });

        cvLayers.addSelectionChangedListener(new ISelectionChangedListener() {

            public void selectionChanged(SelectionChangedEvent event) {
                updateZoomLevels();
                updateGUIFromScale();
            }

        });
        //endregion

        //region Label "Zoom-Level"
        Label lblZoomLevel = new Label(composite, SWT.HORIZONTAL);
        lblZoomLevel.setText(Messages.ZoomLevelSwitcher_ZoomLevel);
        //endregion

        //region Zoom-Level ComboBox
        cvZoomLevels = new ComboViewer(composite, SWT.READ_ONLY);

        cvZoomLevels.setContentProvider(new ArrayContentProvider());
        cvZoomLevels.setLabelProvider(new LabelProvider());
        //endregion

        //region Zoom-In/Zoom-Out Buttons 
        // load icons
        setUpImageCache(parent);

        btnZoomOut = new Button(composite, SWT.PUSH);
        btnZoomOut.setImage(imageCache.get(ICON_ZOOM_OUT));
        btnZoomOut.setToolTipText(Messages.ZoomLevelSwitcher_ZoomOut);

        btnZoomOut.addSelectionListener(new SelectionListener() {

            public void widgetSelected(SelectionEvent e) {
                zoomOut();
            }

            public void widgetDefaultSelected(SelectionEvent e) {
            }
        });

        btnZoomIn = new Button(composite, SWT.PUSH);
        btnZoomIn.setImage(imageCache.get(ICON_ZOOM_IN));
        btnZoomIn.setToolTipText(Messages.ZoomLevelSwitcher_ZoomIn);

        btnZoomIn.addSelectionListener(new SelectionListener() {

            public void widgetSelected(SelectionEvent e) {
                zoomIn();
            }

            public void widgetDefaultSelected(SelectionEvent e) {
            }
        });
        //endregion

        //region Setup listeners
        listenerZoomLevel = new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                zoomToZoomLevel(getSelectedZoomLevel());
            }

        };

        cvZoomLevels.addSelectionChangedListener(listenerZoomLevel);

        setUpMapListeners(ApplicationGIS.getActiveMap());

        getSite().getWorkbenchWindow().getPartService().addPartListener(listenerMapEditor);
        //endregion
    }

    /**
     * Creates the ImageRegistry and adds the two icons.
     */
    private void setUpImageCache(final Composite parent) {
        imageCache = new ImageRegistry(parent.getDisplay());

        ImageDescriptor descZoomOut = ImageDescriptor.createFromFile(getClass(), ICON_ZOOM_OUT_PATH);
        imageCache.put(ICON_ZOOM_OUT, descZoomOut);

        ImageDescriptor descZoomIn = ImageDescriptor.createFromFile(getClass(), ICON_ZOOM_IN_PATH);
        imageCache.put(ICON_ZOOM_IN, descZoomIn);
    }
    //endregion

    //region GUI Helper Methods
    //region Updates to the GUI when the map changed
    private void updateGUI(IMap map) {
        if (parentControl != null && !parentControl.isDisposed()) {
            updateLayerList(map);
            updateZoomLevels();
            updateGUIFromScale();

            parentControl.pack();
        }
    }

    private void updateLayerList(IMap map) {
        if (layerList == null) {
            layerList = new ArrayList<ILayer>();
        }

        // remember the layer which is selected at the moment
        ILayer selectedLayer = getSelectedLayer();

        layerList.clear();

        if (map == null || map == ApplicationGIS.NO_MAP) {
            map = ApplicationGIS.getActiveMap();
        }

        if (map != ApplicationGIS.NO_MAP) {
            List<ILayer> mapLayers = map.getMapLayers();

            // look for layers which have WMTSource as georesource
            for (ILayer layer : mapLayers) {
                if ((layer != null) && (layer.findGeoResource(WMTSource.class) != null)) {
                    // valid layer
                    layerList.add(layer);
                }
            }
        }

        cvLayers.setInput(layerList);
        setSelectedLayer(selectedLayer);

        enableComponents(!layerList.isEmpty());

        // remember to which map these layers belong to
        this.currentMap = map;
    }
    //endregion

    //region Updates to the GUI when another layer was selected
    private void updateZoomLevels() {
        WMTSource wmtSource = getWMTSourceOfSelectedLayer();

        if (wmtSource == null) {
            cvZoomLevels.setInput(null);
        } else {
            int minZoomLevel = wmtSource.getMinZoomLevel();
            int maxZoomLevel = wmtSource.getMaxZoomLevel();

            generateZoomLevels(minZoomLevel, maxZoomLevel);

            cvZoomLevels.setInput(zoomLevels);
        }
    }
    //endregion

    //region Updates to the GUI regarding the scale
    private void updateGUIFromScale() {
        try {
            WMTSource wmtSource = getWMTSourceOfSelectedLayer();

            if (wmtSource != null) {
                // get the zoom-level for this scale
                WMTScaleZoomLevelMatcher zoomLevelMatcher = getZoomLevelMatcher(wmtSource);

                int zoomLevel = wmtSource.getZoomLevelFromMapScale(zoomLevelMatcher, WMTRenderJob.getScaleFactor());

                setSelectedZoomLevel(zoomLevel);
                updateZoomButtons(zoomLevel);
            } else {
                throw new Exception("wmtSource is null"); //$NON-NLS-1$
            }
        } catch (Exception e) {
            WMTPlugin.log("[WMTZoomLevelSwitcher.updateGUIFromScale] Failed ", e); //$NON-NLS-1$
        }
    }
    //endregion

    //region Methods for the zoom-level combo-box
    private void setSelectedZoomLevel(int zoomLevel) {

        List<Integer> selectedZoomLevels = new ArrayList<Integer>(1);
        selectedZoomLevels.add(zoomLevel);
        ISelection selection = new StructuredSelection(selectedZoomLevels);

        cvZoomLevels.removeSelectionChangedListener(listenerZoomLevel);
        cvZoomLevels.setSelection(selection);
        cvZoomLevels.addSelectionChangedListener(listenerZoomLevel);
    }

    private int getSelectedZoomLevel() {
        StructuredSelection selection = (StructuredSelection) cvZoomLevels.getSelection();

        if (selection.isEmpty()) {
            return zoomLevels[0];
        } else {
            return (Integer) selection.getFirstElement();
        }
    }

    private void generateZoomLevels(int minZoomLevel, int maxZoomLevel) {
        int length = maxZoomLevel - minZoomLevel + 1;
        zoomLevels = new Integer[length];

        int zoomLevel = minZoomLevel;
        for (int i = 0; i < length; i++) {
            zoomLevels[i] = zoomLevel++;
        }
    }
    //endregion

    //region Methods for the layer combo-box
    private WMTSource getWMTSourceOfSelectedLayer() {
        ILayer layer = getSelectedLayer();

        if (layer == null)
            return null;

        IGeoResource resource = layer.findGeoResource(WMTSource.class);
        if (resource == null)
            return null;

        try {
            WMTSource wmtSource = resource.resolve(WMTSource.class, null);

            return wmtSource;
        } catch (IOException e) {
            return null;
        }
    }

    private ILayer getSelectedLayer() {
        StructuredSelection selection = (StructuredSelection) cvLayers.getSelection();

        if (selection.isEmpty()) {
            return null;
        } else {
            return (ILayer) selection.getFirstElement();
        }
    }

    private void setSelectedLayer(ILayer layer) {
        if (layer == null || !layerList.contains(layer)) {
            // try to get the first layer
            if (layerList.isEmpty()) {
                // no layer there to select
                return;
            } else {
                layer = layerList.get(0);
            }
        }

        // set the layer selected
        List<ILayer> selectedLayers = new ArrayList<ILayer>(1);
        selectedLayers.add(layer);
        ISelection selection = new StructuredSelection(selectedLayers);

        cvLayers.setSelection(selection);
    }
    //endregion

    //region Methods to disable/enable GUI elements
    private void enableComponents(boolean enabled) {
        cvLayers.getCombo().setEnabled(enabled);
        cvZoomLevels.getCombo().setEnabled(enabled);
        btnZoomIn.setEnabled(enabled);
        btnZoomOut.setEnabled(enabled);
    }

    private void updateZoomButtons(int zoomLevel) {
        boolean zoomInEnabled = true;
        boolean zoomOutEnabled = true;

        if (zoomLevel <= zoomLevels[0]) {
            zoomOutEnabled = false;
        } else if (zoomLevel >= zoomLevels[zoomLevels.length - 1]) {
            zoomInEnabled = false;
        }

        btnZoomIn.setEnabled(zoomInEnabled);
        btnZoomOut.setEnabled(zoomOutEnabled);
    }
    //endregion

    //region Methods to zoom in/out
    private synchronized WMTScaleZoomLevelMatcher getZoomLevelMatcher(WMTSource wmtSource) throws Exception {
        double mapScale = currentMap.getViewportModel().getScaleDenominator();
        ReferencedEnvelope mapExtentMapCrs = currentMap.getViewportModel().getBounds();

        return WMTScaleZoomLevelMatcher.createMatcher(mapExtentMapCrs, mapScale, wmtSource);
    }

    private void zoomIn() {
        int zoomLevel = getSelectedZoomLevel();

        if (zoomLevel < zoomLevels[zoomLevels.length - 1]) {
            zoomToZoomLevel(zoomLevel + 1);
        }
    }

    private void zoomOut() {
        int zoomLevel = getSelectedZoomLevel();

        if (zoomLevel > zoomLevels[0]) {
            zoomToZoomLevel(zoomLevel - 1);
        }
    }

    private void zoomToZoomLevel(int zoomLevel) {
        try {
            WMTSource wmtSource = getWMTSourceOfSelectedLayer();

            if (wmtSource != null) {
                WMTScaleZoomLevelMatcher zoomLevelMatcher = getZoomLevelMatcher(wmtSource);
                double scale = zoomLevelMatcher.getOptimumScaleFromZoomLevel(zoomLevel, wmtSource);

                zoomToScale(scale);
            } else {
                throw new Exception("wmtSource is null"); //$NON-NLS-1$
            }
        } catch (Exception e) {
            WMTPlugin.log("[WMTZoomLevelSwitcher.zoomToZoomLevel] Zooming failed: " + zoomLevel, e); //$NON-NLS-1$
        }
    }

    private void zoomToScale(double scale) {
        ApplicationGIS.getActiveMap().sendCommandASync(new SetScaleCommand(scale));
    }
    //endregion
    //endregion

    @Override
    public void setFocus() {
    }

}