Package org.locationtech.udig.project.ui.internal

Source Code of org.locationtech.udig.project.ui.internal.MapEditor$StatusBarButton

/* uDig - User Friendly Desktop Internet GIS client
* http://udig.refractions.net
* (C) 2004-2012, 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.project.ui.internal;

import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.locationtech.udig.catalog.ITransientResolve;
import org.locationtech.udig.core.internal.ExtensionPointList;
import org.locationtech.udig.internal.ui.IDropTargetProvider;
import org.locationtech.udig.internal.ui.UDIGControlDropListener;
import org.locationtech.udig.internal.ui.UDIGDropHandler;
import org.locationtech.udig.project.EditManagerEvent;
import org.locationtech.udig.project.IEditManagerListener;
import org.locationtech.udig.project.ILayer;
import org.locationtech.udig.project.ILayerListener;
import org.locationtech.udig.project.IMapCompositionListener;
import org.locationtech.udig.project.IMapListener;
import org.locationtech.udig.project.LayerEvent;
import org.locationtech.udig.project.MapCompositionEvent;
import org.locationtech.udig.project.MapEvent;
import org.locationtech.udig.project.command.UndoRedoCommand;
import org.locationtech.udig.project.interceptor.MapInterceptor;
import org.locationtech.udig.project.internal.Layer;
import org.locationtech.udig.project.internal.Map;
import org.locationtech.udig.project.internal.Project;
import org.locationtech.udig.project.internal.ProjectPackage;
import org.locationtech.udig.project.internal.ProjectPlugin;
import org.locationtech.udig.project.internal.commands.ChangeCRSCommand;
import org.locationtech.udig.project.internal.commands.selection.SelectLayerCommand;
import org.locationtech.udig.project.internal.render.RenderManager;
import org.locationtech.udig.project.render.IViewportModelListener;
import org.locationtech.udig.project.render.ViewportModelEvent;
import org.locationtech.udig.project.render.ViewportModelEvent.EventType;
import org.locationtech.udig.project.ui.AnimationUpdater;
import org.locationtech.udig.project.ui.ApplicationGIS;
import org.locationtech.udig.project.ui.IAnimation;
import org.locationtech.udig.project.ui.UDIGEditorInput;
import org.locationtech.udig.project.ui.commands.IDrawCommand;
import org.locationtech.udig.project.ui.controls.ScaleRatioLabel;
import org.locationtech.udig.project.ui.internal.commands.draw.DrawFeatureCommand;
import org.locationtech.udig.project.ui.render.displayAdapter.ViewportPane;
import org.locationtech.udig.project.ui.tool.IMapEditorSelectionProvider;
import org.locationtech.udig.project.ui.tool.IToolManager;
import org.locationtech.udig.project.ui.viewers.MapEditDomain;
import org.locationtech.udig.project.ui.viewers.MapViewer;
import org.locationtech.udig.ui.CRSChooserDialog;
import org.locationtech.udig.ui.IBlockingSelection;
import org.locationtech.udig.ui.PlatformGIS;
import org.locationtech.udig.ui.PreShutdownTask;
import org.locationtech.udig.ui.ProgressManager;
import org.locationtech.udig.ui.ShutdownTaskList;
import org.locationtech.udig.ui.UDIGDragDropUtilities;
import org.locationtech.udig.ui.UDIGDragDropUtilities.DragSourceDescriptor;
import org.locationtech.udig.ui.UDIGDragDropUtilities.DropTargetDescriptor;

import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ContributionItem;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionManager;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.action.StatusLineLayoutData;
import org.eclipse.jface.action.StatusLineManager;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IconAndMessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.SameShellProvider;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.SubActionBars2;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.dialogs.PropertyDialogAction;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.preferences.ScopedPreferenceStore;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

/**
* This class is the Eclipse editor Part in which a ViewportPane is embedded. The ViewportPane
* displays and edits Maps. MapViewport is used to intialize ViewportPane and the RenderManager.
*
* @author Jesse Eichar
* @version $Revision: 1.9 $
*/
public class MapEditor extends EditorPart implements IDropTargetProvider, IAdaptable, MapEditorPart {
    private static final String LAYER_DIRTY_KEY = "DIRTY"; //$NON-NLS-1$
    /** The id of the MapViewport View */
    public final static String ID = "org.locationtech.udig.project.ui.mapEditor"; //$NON-NLS-1$
    final MapEditor editor = this;
    final StatusLineManager statusLineManager = new StatusLineManager();
    private MapEditorSite mapEditorSite;
    private boolean dirty = false;

    // Menu menu;

    // private ViewportPane viewportPane;
    private MapViewer viewer = null;

    /**
     * This composite is used to hold the view; and the status line.
     */
    private Composite composite;

    private DropTargetDescriptor dropTarget;

    /** This is for testing only DO NOT USE OTHERWISE */
    public boolean isTesting;

    private DragSourceDescriptor dragSource;

    /**
     * Creates a new MapViewport object.
     */
    public MapEditor() {
        super();
        // Make sure the featureEditorProcessor has been started.
        ProjectUIPlugin.getDefault().getFeatureEditProcessor();
    }

    public Composite getComposite() {
        return composite;
    }

    /**
     * The layer listener will listen for edit events and mark the
     * map as dirty if the layer is modified.
     */
    ILayerListener layerListener = new ILayerListener(){

        public void refresh( LayerEvent event ) {
            if (event.getType() == LayerEvent.EventType.EDIT_EVENT) {
                setDirty(true);
                event.getSource().getBlackboard().put(LAYER_DIRTY_KEY, "true"); //$NON-NLS-1$
            }
        }

    };
    /**
     * This listener is called when layers are added and removed.
     * <p>
     * This method will add the layerListener to each layer on the map.
     * </p>
     */
    IMapCompositionListener mapCompositionListener = new IMapCompositionListener(){

        @SuppressWarnings("unchecked")
        public void changed( MapCompositionEvent event ) {
            switch( event.getType() ) {
            case MANY_ADDED:
                Collection<ILayer> added = (Collection<ILayer>) event.getNewValue();
                for( ILayer layer : added ) {
                    layer.addListener(layerListener);
                }
                break;
            case MANY_REMOVED:
                Collection<ILayer> removed = (Collection<ILayer>) event.getOldValue();
                for( ILayer layer : removed ) {
                    removeListenerFromLayer(event, layer);
                }
                break;
            case ADDED:

                ((ILayer) event.getNewValue()).addListener(layerListener);
                break;
            case REMOVED:

                ILayer removedLayer = ((ILayer) event.getOldValue());
                removeListenerFromLayer(event, removedLayer);
                break;
            default:
                break;
            }

            boolean dirty = isMapDirty();

            if (dirty != isDirty()) {
                setDirty(dirty);
            }
        }

        private void removeListenerFromLayer( MapCompositionEvent event, ILayer removedLayer ) {
            removedLayer.removeListener(layerListener);
            setDirty(isMapDirty());
        }

    };
    /**
     * Listens to the Map and will change the editor title if the map name
     * is changed. Also marks a layer as ditry if the edit manager has
     * some kind of event.
     */
    IMapListener mapListener = new IMapListener(){

        public void changed( final MapEvent event ) {
            if (composite == null)
                return; // the composite hasn't been created so chill out
            if (getMap() == null || composite.isDisposed()) {
                event.getSource().removeMapListener(this);
                return;
            }

            MapEditor.this.composite.getDisplay().asyncExec(new Runnable(){
                public void run() {
                    switch( event.getType() ) {
                    case NAME:
                        setPartName((String) event.getNewValue()); // rename the map
                        break;
                    case EDIT_MANAGER:
                        for( ILayer layer : event.getSource().getMapLayers() ) {
                            if (layer.hasResource(ITransientResolve.class)) {
                                setDirty(true);
                                break;
                            }
                        }
                        break;
                    default:
                        break;
                    }
                }
            });
        }

    };

    /**
     * Listens to the edito manager; will clear the dirty status after a commit or
     * after a rollback (as long as a map does not have temporary layers).
     */
    IEditManagerListener editListener = new IEditManagerListener(){

        public void changed( EditManagerEvent event ) {
            switch( event.getType() ) {
            case EditManagerEvent.POST_COMMIT:
                if (!hasTemporaryLayers()) {
                    setDirty(false);
                }
                break;
            case EditManagerEvent.POST_ROLLBACK:
                if (!hasTemporaryLayers()) {
                    setDirty(false);
                }
                break;
            default:
                break;
            }
        }

        private boolean hasTemporaryLayers() {
            if (getMap() == null)
                return false;
            List<Layer> layers = getMap().getLayersInternal();
            if (layers == null)
                return false;
            for( Layer layer : layers ) {
                if (layer.hasResource(ITransientResolve.class)) {
                    return true;
                }
            }
            return false;
        }
    };

    private LayerSelectionListener layerSelectionListener;

    private ReplaceableSelectionProvider replaceableSelectionProvider;
    private PreShutdownTask shutdownTask = new PreShutdownTask(){

        public int getProgressMonitorSteps() {
            return 3;
        }

        public boolean handlePreShutdownException( Throwable t, boolean forced ) {
            ProjectUIPlugin.log("error prepping map editors for shutdown", t); //$NON-NLS-1$
            return true;
        }

        public boolean preShutdown( IProgressMonitor monitor, IWorkbench workbench, boolean forced )
                throws Exception {
            monitor.beginTask("Saving Map Editor", 3); //$NON-NLS-1$
            save(new SubProgressMonitor(monitor, 1));
            if (dirty) {
                if (!forced) {
                    return false;
                } else {
                    setDirty(false);
                }
            }
            removeTemporaryLayers(ProjectPlugin.getPlugin().getPreferenceStore());
            monitor.worked(1);

            // save the map's URI in the preferences so that it will be loaded the next time udig is
            // run.
            Resource resource = getMap().eResource();
            if (resource != null) {
                // save editor
                try {
                    IPreferenceStore p = ProjectUIPlugin.getDefault().getPreferenceStore();
                    int numEditors = p.getInt(ID);
                    String id = ID + ":" + numEditors; //$NON-NLS-1$
                    numEditors++;
                    p.setValue(ID, numEditors);
                    String value = resource.getURI().toString();
                    p.setDefault(id, ""); //$NON-NLS-1$
                    p.setValue(id, value);
                } catch (Exception e) {
                    ProjectUIPlugin.log("Failure saving which maps are open", e); //$NON-NLS-1$
                }
            }

            monitor.worked(1);
            monitor.done();

            return true;
        }

        private void save( final IProgressMonitor monitor ) {
            if (dirty) {
                PlatformGIS.syncInDisplayThread(new Runnable(){
                    public void run() {
                        IconAndMessageDialog d = new SaveDialog(Display.getCurrent()
                                .getActiveShell(), getMap());
                        int result = d.open();

                        if (result == IDialogConstants.YES_ID)
                            doSave(monitor);
                        else if (result != Window.CANCEL) {
                            setDirty(false);
                        }
                    }
                });
            }
        }

    };

    public Object getAdapter( Class adaptee ) {
        if (adaptee.isAssignableFrom(Map.class)) {
            return getMap();
        }
        if (adaptee.isAssignableFrom(ViewportPane.class)) {
            return viewer.getViewport();
        }
        return super.getAdapter(adaptee);
    }

    private void clearLayerDirtyFlag() {
        List<ILayer> layers = getMap().getMapLayers();
        for( ILayer layer : layers ) {
            layer.getBlackboard().put(LAYER_DIRTY_KEY, null);
        }
    }

    public void setFont( Control control ) {
        viewer.setFont(control);
        /*
        Display display = control.getDisplay();
        FontData[] data = display.getFontList("courier", true); //$NON-NLS-1$
        if (data.length <1) {
            data=control.getFont().getFontData();
        }
        for( int i = 0; i < data.length; i++ ) {
            if ( Platform.OS_MACOSX == Platform.getOS() )
                data[i].setHeight(12);
            else
                data[i].setHeight(10);
        }
        control.setFont(new Font(control.getDisplay(), data));
        */
    }

    /**
     * Displays a the current CRS and allows to change it
     */
    class StatusBarButton extends ContributionItem {
        static final String CRS_ITEM_ID = "CRS Display"; //$NON-NLS-1$

        static final String BOUNDS_ITEM_ID = "Bounds Display"; //$NON-NLS-1$
        static final int MAX_LENGTH = 12;
        private Button button;
        private String value;

        private String full;

        /**
         * Create new StatusBarLabel object
         */
        public StatusBarButton( String id, String initialValue ) {
            super(id);
            setText(initialValue);
        }

        /**
         * sets the current text.
         */
        public void setText( String text ) {
            value = text;
            full = value;
            if (value.length() > MAX_LENGTH) {
                int start2 = value.length() - 6;
                value = value.substring(0, 6) + "..." + value.substring(start2, value.length()); //$NON-NLS-1$
                System.out.println(value.length());
            }
            if (button != null && !button.isDisposed()) {
                button.setText(value);
            }
        }
        /**
         * @see org.eclipse.jface.action.IContributionItem#isDynamic()
         */
        public boolean isDynamic() {
            return true;
        }
        /**
         * @see org.eclipse.jface.action.ContributionItem#dispose()
         */
        public void dispose() {
            if (button != null)
                button.dispose();
            if (popup != null)
                popup.dispose();
        }
        /**
         * @see org.eclipse.jface.action.ContributionItem#fill(org.eclipse.swt.widgets.Composite)
         */
        @Override
        public void fill( Composite c ) {
            Label separator = new Label(c, SWT.SEPARATOR);
            StatusLineLayoutData data = new StatusLineLayoutData();
            separator.setLayoutData(data);
            data.widthHint = 1;
            data.heightHint = ScaleRatioLabel.STATUS_LINE_HEIGHT;
            button = new Button(c, SWT.PUSH | SWT.FLAT);
            setFont(button);
            data = new StatusLineLayoutData();
            button.setLayoutData(data);
            button.setText(value);
            button.addListener(SWT.Selection, new Listener(){

                public void handleEvent( Event event ) {
                    promptForCRS();
                }

            });
            button.addListener(SWT.MouseEnter, new Listener(){
                public void handleEvent( final Event event ) {
                    showFullText();
                }
            });
            data.widthHint = 132;
            data.heightHint = ScaleRatioLabel.STATUS_LINE_HEIGHT;
        }
        Label textLabel;
        Shell popup;

        private void promptForCRS() {
            /*
            CRSPropertyPage page = new CRSPropertyPage();
            page.setStrategy(new CRSPropertyPage.MapStrategy(getMap()));
            PreferenceManager mgr = new PreferenceManager();
            IPreferenceNode node = new PreferenceNode("1", page); //$NON-NLS-1$
            mgr.addToRoot(node);

            PreferenceDialog pdialog = new PreferenceDialog(getSite().getShell(), mgr);
            ZoomingDialog dialog = new ZoomingDialog(getSite().getShell(), pdialog, ZoomingDialog
                    .calculateBounds(button));
            dialog.open();
            */
            CoordinateReferenceSystem crs = getMap().getViewportModel().getCRS();           
            CRSChooserDialog dialog = new CRSChooserDialog( getSite().getShell(), crs );
            int code = dialog.open();
            if( Window.OK == code ){
                CoordinateReferenceSystem result = dialog.getResult();
                if( !result.equals(crs)){
                    getMap().sendCommandSync(new ChangeCRSCommand(result));
                    updateCRS();
                }
            }

        }

        void showFullText() {
            final Display display = button.getDisplay();
            if (popup == null) {
                popup = new Shell(display.getActiveShell(), SWT.NO_FOCUS | SWT.ON_TOP);
                popup.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
                popup.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
                popup.setLayout(new RowLayout());
                Composite composite = new Composite(popup, SWT.NONE);
                composite.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
                composite.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
                composite.setLayout(new RowLayout());
                textLabel = new Label(popup, SWT.NONE);
                textLabel.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
                textLabel.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
                textLabel.setFont(button.getFont());

            }
            Point location = statusLineManager.getControl().toDisplay(button.getLocation());
            location.y = location.y - ScaleRatioLabel.STATUS_LINE_HEIGHT;
            if (popup.isDisposed()) {
                return;
            }
            popup.setLocation(location);
            textLabel.setText(full);
            popup.setVisible(true);
            popup.pack(true);
            display.timerExec(500, new Runnable(){
                public void run() {
                    checkforMouseOver(display);
                }
            });
        }

        private void checkforMouseOver( final Display display ) {
            if (display.getCursorControl() == button) {
                display.timerExec(500, new Runnable(){
                    public void run() {
                        if (display.getCursorControl() == button) {
                            checkforMouseOver(display);
                        } else {
                            popup.setVisible(false);
                        }
                    }
                });
            } else {
                popup.setVisible(false);
            }

        }

        /**
         * Get current text.
         */
        public String getText() {
            return full;
        }
    }

    /**
     * Updates the crs label in the statusbar.
     */
    protected void updateCRS() {
        Map map = getMap();
        if (map == null) {
            getSite().getPage().closeEditor(this, false);
            return;
        }
        CoordinateReferenceSystem crs = map.getViewportModel().getCRS();
        if (crs == null || crs.getName() == null) {
            return;
        }

        final String full = crs.getName().getCode();
        if (full == null || isSame(full))
            return;

        Display display = PlatformUI.getWorkbench().getDisplay();
        if (display == null)
            display = Display.getDefault();

        display.asyncExec(new Runnable(){
            public void run() {

                IContributionManager bar = mapEditorSite.getActionBars().getStatusLineManager();
                if (bar == null)
                    return;
                StatusBarButton label = (StatusBarButton) bar.find(StatusBarButton.CRS_ITEM_ID);
                if (label == null) {
                    label = new StatusBarButton(StatusBarButton.CRS_ITEM_ID, full);
                    bar.appendToGroup(StatusLineManager.MIDDLE_GROUP, label);
                    label.setVisible(true);
                    bar.update(true);
                    return;
                }
                label.setText(full);
            }
        });

    }

    /**
     * Makes sure the scale is displayed
     */
    protected void updateScaleLabel() {
        if (composite.isDisposed())
            return;
        if (Display.getCurrent() != null) {
            doUpdateScaleLabel();
            return;
        }
        Display display = PlatformUI.getWorkbench().getDisplay();
        if (display == null)
            display = Display.getDefault();
        display.asyncExec(new Runnable(){
            public void run() {
                doUpdateScaleLabel();
            }

        });

    }
    void doUpdateScaleLabel() {
        IContributionManager bar = mapEditorSite.getActionBars().getStatusLineManager();
        if (bar == null)
            return;
        ScaleRatioLabel label = (ScaleRatioLabel) bar.find(ScaleRatioLabel.SCALE_ITEM_ID);
        if (label == null) {
            label = new ScaleRatioLabel(this);
            bar.appendToGroup(StatusLineManager.MIDDLE_GROUP, label);
            label.setVisible(true);
            bar.update(true);
        }
        label.setViewportModel(getMap().getViewportModel());
    }

    private boolean isSame( String crs ) {
        IContributionManager bar = getActionbar().getStatusLineManager();

        if (bar != null) {
            StatusBarButton label = (StatusBarButton) bar.find(StatusBarButton.CRS_ITEM_ID);
            if (label != null && crs.equals(label.getText()))
                return true;
        }
        return false;
    }

    /**
     * @see org.eclipse.ui.IWorkbenchPart#dispose()
     */
    public void dispose() {

        if (isTesting)
            return;
        if (getSite() == null || getSite().getPage() == null) {
            // Exception occurred before instantiating editor
            return;
        }

        runMapClosingInterceptors();

        deregisterFeatureFlasher();
        getSite().getPage().removePartListener(partlistener);
        viewer.getViewport().removePaneListener(getMap().getViewportModelInternal());
        getMap().getViewportModelInternal().setInitialized(false);

        selectFeatureListener = null;
        partlistener = null;

        if (statusLineManager != null)
            statusLineManager.dispose();

        final ScopedPreferenceStore store = ProjectPlugin.getPlugin().getPreferenceStore();
        if (!PlatformUI.getWorkbench().isClosing()) {
            ShutdownTaskList.instance().removePreShutdownTask(shutdownTask);
            try {
                // kill rending now - even if it is moving
                getRenderManager().dispose();
            } catch (Throwable t) {
                ProjectUIPlugin.log("Shutting down rendering - " + t, null);
            }
            getMap().getEditManagerInternal().setEditFeature(null, null);
            try {
                PlatformGIS.run(new ISafeRunnable(){

                    public void handleException( Throwable exception ) {
                        ProjectUIPlugin.log("error saving map: " + getMap().getName(), exception); //$NON-NLS-1$
                    }

                    public void run() throws Exception {

                        removeTemporaryLayers(store);
                        Project p = getMap().getProjectInternal();
                        if (p != null) {
                            if (p.eResource() != null && p.eResource().isModified()) {
                                p.eResource().save(ProjectPlugin.getPlugin().saveOptions);
                            }

                            final Resource resource = getMap().eResource();
                            resource.save(ProjectPlugin.getPlugin().saveOptions);

                            // need to kick the Project so viewers will update
                            p.eNotify(new ENotificationImpl((InternalEObject) p, Notification.SET,
                                    ProjectPackage.PROJECT__ELEMENTS_INTERNAL, null, null));

                        } else {
                            final Resource resource = getMap().eResource();
                            if (resource != null)
                                resource.save(ProjectPlugin.getPlugin().saveOptions);
                        }
                        viewer.dispose();
                        // setMap(null);
                    }

                });
            } catch (Exception e) {
                ProjectPlugin.log("Exception while saving Map", e); //$NON-NLS-1$
            }
        }

        super.dispose();

    }

    private void runMapClosingInterceptors() {
        List<IConfigurationElement> interceptors = ExtensionPointList
                .getExtensionPointList(MapInterceptor.MAP_INTERCEPTOR_EXTENSIONPOINT);
        for( IConfigurationElement element : interceptors ) {
            if (!MapInterceptor.CLOSING_ID.equals(element.getName())) //$NON-NLS-1$
                continue;
            try {
                MapInterceptor interceptor = (MapInterceptor) element
                        .createExecutableExtension("class"); //$NON-NLS-1$
                interceptor.run(getMap());
            } catch (Exception e) {
                ProjectPlugin.log("", e); //$NON-NLS-1$
            }
        }
    }

    private void removeTemporaryLayers( IPreferenceStore store ) {
        if (store
                .getBoolean(org.locationtech.udig.project.preferences.PreferenceConstants.P_REMOVE_LAYERS)) {
            List<Layer> layers = getMap().getLayersInternal();
            List<Layer> layersToRemove = new ArrayList<Layer>();
            for( Layer layer : layers ) {
                if (layer.getGeoResources().get(0).canResolve(ITransientResolve.class)) {
                    layersToRemove.add(layer);
                }
            }

            if (!layers.isEmpty()) {
                if (getMap().eResource() != null)
                    getMap().eResource().setModified(true);
                layers.removeAll(layersToRemove);
            }
        }
    }

    /**
     * @see org.eclipse.ui.ISaveablePart#doSave(org.eclipse.core.runtime.IProgressMonitor)
     */
    public void doSave( IProgressMonitor monitor ) {
        final boolean[] success = new boolean[]{false};

        PlatformGIS.syncInDisplayThread(new SaveMapRunnable(this, success));

        if (success[0]) {
            setDirty(false);
        } else {
            // abort shutdown if in progress
            monitor.setCanceled(true);
        }
    }

    /**
     * @see org.eclipse.ui.ISaveablePart#doSaveAs()
     */
    public void doSaveAs() {
    }

    /**
     * @see org.eclipse.ui.IEditorPart#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
     */
    public void init( IEditorSite site, IEditorInput input ) {
        setSite(site);
        setInput(input);
        // initialize ToolManager
        ApplicationGIS.getToolManager();
    }

    /**
     * @see org.eclipse.ui.part.EditorPart#setInput(org.eclipse.ui.IEditorInput)
     */
    protected void setInput( IEditorInput input ) {
        if (getEditorInput() != null) {
            Map map = (Map) ((UDIGEditorInput) getEditorInput()).getProjectElement();
            if (viewer != null) {
                viewer.setMap(null);
            }
            map.removeMapCompositionListener(mapCompositionListener);
            map.removeMapListener(mapListener);
            map.getEditManager().removeListener(editListener);
        }
        super.setInput(input);
        if (input != null) {
            if (viewer != null) {
                viewer.setMap((Map) ((UDIGEditorInput) input).getProjectElement());
            }
            getMap().addMapCompositionListener(mapCompositionListener);
            getMap().addMapListener(mapListener);
            getMap().getEditManager().addListener(editListener);
        }

    }

    /**
     * @see org.eclipse.ui.ISaveablePart#isDirty()
     */
    public boolean isDirty() {
        return dirty;
    }

    private boolean isMapDirty() {
        boolean dirty = false;
        for( ILayer layer : getMap().getMapLayers() ) {
            if (layer.hasResource(ITransientResolve.class)) {
                dirty = true;
            }
            boolean layerIsDirty = layer.getBlackboard().get(LAYER_DIRTY_KEY) != null;
            if (layerIsDirty) {
                dirty = true;
            }
        }
        return dirty;
    }

    /**
     * @see org.eclipse.ui.ISaveablePart#isSaveAsAllowed()
     */
    public boolean isSaveAsAllowed() {
        return true;
    }

    public void setDirty( boolean dirty ) {
        if (dirty == this.dirty)
            return;

        this.dirty = dirty;

        if (!dirty) {
            clearLayerDirtyFlag();
        }

        Display.getDefault().asyncExec(new Runnable(){
            /**
             * @see java.lang.Runnable#run()
             */
            @SuppressWarnings("synthetic-access")
            public void run() {
                firePropertyChange(PROP_DIRTY);
            }
        });
    }

    /**
     * @see org.eclipse.ui.part.EditorPart#isSaveOnCloseNeeded()
     */
    public boolean isSaveOnCloseNeeded() {
        return true;
    }

    /**
     * @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
     */
    public void createPartControl( final Composite parent ) {

        ShutdownTaskList.instance().addPreShutdownTask(shutdownTask);

        composite = new Composite(parent, SWT.NO_BACKGROUND);

        composite.setLayout(new FormLayout());
        composite.setFont(parent.getFont());
        setPartName(getMap().getName());

        setTitleToolTip(Messages.MapEditor_titleToolTip);
        setTitleImage(ProjectUIPlugin.getDefault().getImage(ISharedImages.MAP_OBJ));

        final IPreferenceStore preferenceStore = ProjectPlugin.getPlugin().getPreferenceStore();
        boolean istiled = preferenceStore
                .getBoolean(org.locationtech.udig.project.preferences.PreferenceConstants.P_TILED_RENDERING);

        if (!istiled) {
            viewer = new MapViewer(composite, SWT.DOUBLE_BUFFERED);
        } else {
            viewer = new MapViewer(composite, SWT.MULTI | SWT.NO_BACKGROUND);
        }
        // allow the viewer to open our context menu; work with our selection proivder etc
        viewer.init(this);
        // if a map was provided as input we can ask the viewer to use it
        Map input = (Map) ((UDIGEditorInput) getEditorInput()).getProjectElement();
        if (input != null) {
            viewer.setMap(input);
        }

        FormData formdata = new FormData();
        formdata.top = new FormAttachment(0);
        formdata.bottom = new FormAttachment(100, -ScaleRatioLabel.STATUS_LINE_HEIGHT);
        formdata.left = new FormAttachment(0);
        formdata.right = new FormAttachment(100);
        viewer.getViewport().getControl().setLayoutData(formdata);

        statusLineManager.add(new GroupMarker(StatusLineManager.BEGIN_GROUP));
        statusLineManager.add(new GroupMarker(StatusLineManager.MIDDLE_GROUP));
        statusLineManager.add(new GroupMarker(StatusLineManager.END_GROUP));
        statusLineManager.createControl(composite, SWT.BORDER);
        formdata = new FormData();
        formdata.left = new FormAttachment(0);
        formdata.right = new FormAttachment(100);
        formdata.top = new FormAttachment(viewer.getViewport().getControl(), 0, SWT.BOTTOM);
        formdata.bottom = new FormAttachment(100);
        statusLineManager.getControl().setLayoutData(formdata);

        getSite().getPage().addPartListener(partlistener);
        registerFeatureFlasher();
        /*
        if (getMap().getRenderManager() == null){
            if (!istiled) {
                getMap().setRenderManagerInternal(new RenderManagerDynamic());
            } else {
                getMap().setRenderManagerInternal(new TiledRenderManagerDynamic());
            }
        }

        setRenderManager(getMap().getRenderManagerInternal());
        viewer.getViewport().setRenderManager(getRenderManager());
        getRenderManager().setMapDisplay(viewer.getViewport());
        */
        viewer.getViewport().addPaneListener(getMap().getViewportModelInternal());

        layerSelectionListener = new LayerSelectionListener(new LayerSelectionListener.Callback(){

            public void callback( List<Layer> layers ) {
                if (composite.isDisposed()) {
                    getSite().getPage().removePostSelectionListener(layerSelectionListener);
                    return; // component.isVisible cannot be called on a disposed component
                } else if (!composite.isVisible())
                    return;
                Layer layer = layers.get(0);
                // Second condition excludes unnecessary UI call
                if (layer.getMap() == getMap()
                        && getMap().getEditManager().getSelectedLayer() != layer) {
                    SelectLayerCommand selectLayerCommand = new SelectLayerCommand(layer);
                    selectLayerCommand.setMap(getMap());
                    try {
                        selectLayerCommand.run(ProgressManager.instance().get());
                    } catch (Exception e) {
                        throw (RuntimeException) new RuntimeException().initCause(e);
                    }
                    getMap().sendCommandSync(new UndoRedoCommand(selectLayerCommand));
                }
            }

        });
        getSite().getPage().addPostSelectionListener(layerSelectionListener);

        for( Layer layer : getMap().getLayersInternal() ) {
            layer.addListener(layerListener);
        }

        dropTarget = UDIGDragDropUtilities.addDropSupport(viewer.getViewport().getControl(), this);
        this.replaceableSelectionProvider = new ReplaceableSelectionProvider();
        getSite().setSelectionProvider(replaceableSelectionProvider);
        runMapOpeningInterceptor(getMap());
        mapEditorSite = new MapEditorSite(super.getSite(), this);
        updateCRS();
        updateScaleLabel();

        getMap().getViewportModel().addViewportModelListener(new IViewportModelListener(){

            public void changed( ViewportModelEvent event ) {
                if (getMap() == null) {
                    event.getSource().removeViewportModelListener(this);
                    return;
                }
                if (event.getType() == EventType.CRS) {
                    updateCRS();
                }
            }

        });

        setDirty(isMapDirty());
    }

    private void runMapOpeningInterceptor( Map map ) {
        List<IConfigurationElement> interceptors = ExtensionPointList
                .getExtensionPointList(MapInterceptor.MAP_INTERCEPTOR_EXTENSIONPOINT);
        for( IConfigurationElement element : interceptors ) {
            if (!MapInterceptor.OPENING_ID.equals(element.getName())) //$NON-NLS-1$
                continue;
            try {
                MapInterceptor interceptor = (MapInterceptor) element
                        .createExecutableExtension("class"); //$NON-NLS-1$
                interceptor.run(map);
            } catch (Exception e) {
                ProjectPlugin.log("", e); //$NON-NLS-1$
            }
        }
    }

    private FlashFeatureListener selectFeatureListener = new FlashFeatureListener();
    private boolean flashFeatureRegistered = false;
    private Action propertiesAction;
    /**
     * registers a listener with the current page that flashes a feature each time the current
     * selected feature changes.
     */
    protected synchronized void registerFeatureFlasher() {
        if (!flashFeatureRegistered) {
            flashFeatureRegistered = true;
            IWorkbenchPage page = getSite().getPage();
            page.addPostSelectionListener(selectFeatureListener);
        }
    }

    protected synchronized void deregisterFeatureFlasher() {
        flashFeatureRegistered = false;
        getSite().getPage().removePostSelectionListener(selectFeatureListener);
    }

    void createContextMenu() {
        Menu menu;
        menu = viewer.getMenu();
        if (menu == null) {
            final MenuManager contextMenu = new MenuManager();
            contextMenu.setRemoveAllWhenShown(true);
            contextMenu.addMenuListener(new IMenuListener(){
                public void menuAboutToShow( IMenuManager mgr ) {
                    IToolManager tm = ApplicationGIS.getToolManager();
                   
                    contextMenu.add(tm.getENTERAction());
                    contextMenu.add(new Separator());
                   
                    contextMenu.add(tm.getZOOMTOSELECTEDAction());
                    contextMenu.add(new Separator());
                    contextMenu.add(tm.getBACKWARD_HISTORYAction());
                    contextMenu.add(tm.getFORWARD_HISTORYAction());
                    contextMenu.add(new Separator());
                    // contextMenu.add(tm.createCUTAction(MapEditor.this));
                    contextMenu.add(tm.getCOPYAction(MapEditor.this));
                    contextMenu.add(tm.getPASTEAction(MapEditor.this));
                    contextMenu.add(tm.getDELETEAction());

                    /*
                     * Gets contributions from active modal tool if possible
                     */
                    tm.contributeActiveModalTool(contextMenu);

                    contextMenu.add(new Separator());
                    contextMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
                    if (getMap().getEditManager().getEditFeature() != null) {
                        contextMenu.add(ProjectUIPlugin.getDefault().getFeatureEditProcessor()
                                .getEditFeatureAction(
                                        getSite().getSelectionProvider().getSelection()));

                        contextMenu.add(ProjectUIPlugin.getDefault().getFeatureEditProcessor()
                                .getEditWithFeatureMenu(
                                        getSite().getSelectionProvider().getSelection()));
                    }
                    contextMenu.add(ApplicationGIS.getToolManager().createOperationsContextMenu(
                            replaceableSelectionProvider.getSelection()));
                    contextMenu.add(new Separator());
                    contextMenu.add(ActionFactory.EXPORT.create(getSite().getWorkbenchWindow()));
                    contextMenu.add(new Separator());
                    contextMenu.add(getPropertiesAction());
                }
            });

            // Create menu.
            menu = contextMenu.createContextMenu(composite);
            viewer.setMenu(menu);
            getSite().registerContextMenu(contextMenu, getSite().getSelectionProvider());
        }
    }

    protected IAction getPropertiesAction() {
        if (propertiesAction == null) {
            final Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
            final PropertyDialogAction tmp = new PropertyDialogAction(new SameShellProvider(shell),
                    new ISelectionProvider(){

                        public void addSelectionChangedListener( ISelectionChangedListener listener ) {
                        }

                        public ISelection getSelection() {
                            return new StructuredSelection(getMap());
                        }

                        public void removeSelectionChangedListener(
                                ISelectionChangedListener listener ) {
                        }

                        public void setSelection( ISelection selection ) {
                        }

                    });

            propertiesAction = new Action(){
                @Override
                public void runWithEvent( Event event ) {
                    tmp.createDialog().open();
                }
            };

            propertiesAction.setText(tmp.getText());
            propertiesAction.setActionDefinitionId(tmp.getActionDefinitionId());
            propertiesAction.setDescription(tmp.getDescription());
            propertiesAction.setHoverImageDescriptor(tmp.getHoverImageDescriptor());
            propertiesAction.setImageDescriptor(tmp.getImageDescriptor());
            propertiesAction.setToolTipText(tmp.getToolTipText());

        }
        getEditorSite().getActionBars().setGlobalActionHandler(ActionFactory.PROPERTIES.getId(),
                propertiesAction);
        return propertiesAction;
    }

    /**
     * @see org.eclipse.ui.IWorkbenchPart#setFocus()
     */
    public void setFocus() {
        composite.setFocus();
        updateCRS();
        updateScaleLabel();
    }

    /**
     * Returns the map that this editor edits
     *
     * @return Returns the map that this editor edits
     */
    public Map getMap() {
        // return viewer.getMap();
        UDIGEditorInput editorInput = (UDIGEditorInput) getEditorInput();
        if (editorInput != null) {
            return (Map) editorInput.getProjectElement();
        } else {
            return null;
        }
    }

    /**
     * Returns the ActionbarContributor for the Editor.
     *
     * @return the ActionbarContributor for the Editor.
     */
    public SubActionBars2 getActionbar() {
        return (SubActionBars2) getEditorSite().getActionBars();
    }

    IPartListener2 partlistener = new IPartListener2(){
        public void partActivated( IWorkbenchPartReference partRef ) {
            if (partRef.getPart(false) == MapEditor.this) {
                registerFeatureFlasher();
                ApplicationGIS.getToolManager().setCurrentEditor(editor);
            }
        }

        public void partBroughtToTop( IWorkbenchPartReference partRef ) {
        }

        public void partClosed( IWorkbenchPartReference partRef ) {
            if (partRef.getPart(false) == MapEditor.this) {
                deregisterFeatureFlasher();
                visible = false;
            }
        }

        public void partDeactivated( IWorkbenchPartReference partRef ) {
            // do nothing
        }

        public void partOpened( IWorkbenchPartReference partRef ) {
            // do nothing
        }

        public void partHidden( IWorkbenchPartReference partRef ) {
            if (partRef.getPart(false) == MapEditor.this) {
                deregisterFeatureFlasher();
                visible = false;
            }
        }

        public void partVisible( IWorkbenchPartReference partRef ) {
            if (partRef.getPart(false) == MapEditor.this) {
                registerFeatureFlasher();
                visible = true;
            }
        }

        public void partInputChanged( IWorkbenchPartReference partRef ) {
        }

    };

    private boolean draggingEnabled;
    private volatile boolean visible = false;
  private MapEditDomain editDomain;

    /**
     * Opens the map's context menu.
     */
    public void openContextMenu() {
        viewer.openContextMenu();
        /*getEditorSite().getShell().getDisplay().asyncExec(new Runnable(){
            public void run() {
                menu.setVisible(true);
            }
        });
        */
    }

    public UDIGDropHandler getDropHandler() {
        return ((UDIGControlDropListener) dropTarget.listener).getHandler();
    }

    public Object getTarget( DropTargetEvent event ) {
        return this;
    }

    /**
     * Enables or disables dragging (drag and drop) from the map editor.
     */
    public void setDragging( boolean enable ) {
        if (draggingEnabled == enable)
            return;
        if (enable) {
            dragSource = UDIGDragDropUtilities.addDragSupport(viewer.getViewport().getControl(),
                    getSite().getSelectionProvider());
        } else {
            dragSource.source.dispose();
        }
        draggingEnabled = enable;
    }

    public boolean isDragging() {
        return draggingEnabled;
    }

    @Override
    public String toString() {
        return getTitle();
    }

    public void setSelectionProvider( IMapEditorSelectionProvider selectionProvider ) {
        if (selectionProvider == null) {
            throw new NullPointerException("selection provider must not be null!"); //$NON-NLS-1$
        }
        selectionProvider.setActiveMap(getMap(), this);
        if (selectionProvider != this.replaceableSelectionProvider.getSelectionProvider()) {
            this.replaceableSelectionProvider.setProvider(selectionProvider);
        }
        createContextMenu();
    }

    public MapEditorSite getMapEditorSite() {
        return mapEditorSite;
    }

    private class FlashFeatureListener implements ISelectionListener {

        public void selectionChanged( IWorkbenchPart part, final ISelection selection ) {
            if (part == MapEditor.this || getSite().getPage().getActivePart() != part
                    || selection instanceof IBlockingSelection)
                return;

            ISafeRunnable sendAnimation = new ISafeRunnable(){
                public void run() {
                    if (selection instanceof IStructuredSelection) {
                        IStructuredSelection s = (IStructuredSelection) selection;
                        List<SimpleFeature> features = new ArrayList<SimpleFeature>();
                        for( Iterator iter = s.iterator(); iter.hasNext(); ) {
                            Object element = iter.next();

                            if (element instanceof SimpleFeature) {
                                SimpleFeature feature = (SimpleFeature) element;
                                features.add(feature);
                            }
                        }
                        if (features.size() == 0)
                            return;
                        if (!getRenderManager().isDisposed()) {
                            IAnimation anim = createAnimation(features);
                            if (anim != null)
                                AnimationUpdater.runTimer(getMap().getRenderManager()
                                        .getMapDisplay(), anim);
                        }
                    }
                }
                public void handleException( Throwable exception ) {
                    ProjectUIPlugin.log("Exception preparing animation", exception); //$NON-NLS-1$
                }
            };

            try {
                sendAnimation.run();
            } catch (Exception e) {
                ProjectUIPlugin.log("", e); //$NON-NLS-1$
            }
            // PlatformGIS.run(sendAnimation);
        }

        private IAnimation createAnimation( List<SimpleFeature> current ) {
            final List<IDrawCommand> commands = new ArrayList<IDrawCommand>();
            for( SimpleFeature feature : current ) {
                if (feature == null || feature.getFeatureType().getGeometryDescriptor() == null)
                    continue;
                DrawFeatureCommand command = null;
                if (feature instanceof IAdaptable) {
                    Layer layer = (Layer) ((IAdaptable) feature).getAdapter(Layer.class);
                    if (layer != null)
                        try {
                            command = new DrawFeatureCommand(feature, layer);
                        } catch (IOException e) {
                            // do nothing... thats life
                        }
                }
                if (command == null) {
                    command = new DrawFeatureCommand(feature);
                }
                command.setMap(getMap());
                command.preRender();
                commands.add(command);
            }
            Rectangle2D rect = new Rectangle();
            // for( IDrawCommand command : commands ) {
            // rect=rect.createUnion(command.getValidArea());
            // }
            final Rectangle validArea = (Rectangle) rect;

            return new FeatureAnimation(commands, validArea);
        }
    }

    public boolean isVisible() {
        return visible;
    }

    RenderManager getRenderManager() {
        return viewer.getRenderManager();
    }
    public IStatusLineManager getStatusLineManager() {
      return statusLineManager;
    }
    //
    // helper method for ToolManager
    @Override
    public boolean isTesting() {
        return this.isTesting;
    }
    @Override
    public void setTesting( boolean testing ) {
        this.isTesting = testing;
    }

}
TOP

Related Classes of org.locationtech.udig.project.ui.internal.MapEditor$StatusBarButton

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.