org.kalypso.ui.editor.mapeditor.AbstractMapPart.java Source code

Java tutorial

Introduction

Here is the source code for org.kalypso.ui.editor.mapeditor.AbstractMapPart.java

Source

/*----------------    FILE HEADER KALYPSO ------------------------------------------
 *
 *  This file is part of kalypso.
 *  Copyright (C) 2004 by:
 *
 *  Technical University Hamburg-Harburg (TUHH)
 *  Institute of River and coastal engineering
 *  Denickestrae 22
 *  21073 Hamburg, Germany
 *  http://www.tuhh.de/wb
 *
 *  and
 *
 *  Bjoernsen Consulting Engineers (BCE)
 *  Maria Trost 3
 *  56070 Koblenz, Germany
 *  http://www.bjoernsen.de
 *
 *  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; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  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.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *  Contact:
 *
 *  E-Mail:
 *  belger@bjoernsen.de
 *  schlienger@bjoernsen.de
 *  v.doemming@tuhh.de
 *
 *  ---------------------------------------------------------------------------*/
package org.kalypso.ui.editor.mapeditor;

import java.awt.event.FocusAdapter;
import java.net.URL;

import org.apache.commons.lang3.ObjectUtils;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.StatusLineContributionItem;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IStorageEditorInput;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.kalypso.contribs.eclipse.core.runtime.StatusUtilities;
import org.kalypso.core.KalypsoCorePlugin;
import org.kalypso.metadoc.IExportableObjectFactory;
import org.kalypso.ogc.gml.GisTemplateHelper;
import org.kalypso.ogc.gml.GisTemplateMapModell;
import org.kalypso.ogc.gml.IKalypsoLayerModell;
import org.kalypso.ogc.gml.map.BaseMapSchedulingRule;
import org.kalypso.ogc.gml.map.IMapPanel;
import org.kalypso.ogc.gml.map.MapPanel;
import org.kalypso.ogc.gml.map.MapPanelSourceProvider;
import org.kalypso.ogc.gml.map.listeners.IMapPanelListener;
import org.kalypso.ogc.gml.map.listeners.MapPanelAdapter;
import org.kalypso.ogc.gml.mapmodel.IMapPanelProvider;
import org.kalypso.ogc.gml.selection.IFeatureSelectionManager;
import org.kalypso.template.gismapview.Gismapview;
import org.kalypso.ui.KalypsoGisPlugin;
import org.kalypso.ui.editor.AbstractWorkbenchPart;
import org.kalypso.ui.internal.i18n.Messages;
import org.kalypso.util.command.JobExclusiveCommandTarget;
import org.kalypsodeegree.KalypsoDeegreePlugin;
import org.kalypsodeegree.model.geometry.GM_Envelope;

/**
 * Abstract superclass for map editor and map view. Inherits from AbstractEditorPart for editor behavior (save when
 * dirty, command target). Based on the old {@link GisMapEditor} implementation.
 * 
 * @author Stefan Kurzbach
 */
public abstract class AbstractMapPart extends AbstractWorkbenchPart implements IMapPanelProvider {
    // TODO: we probably should move this elsewhere
    public static final String MAP_COMMAND_CATEGORY = "org.kalypso.ogc.gml.map.category"; //$NON-NLS-1$

    private final IFeatureSelectionManager m_selectionManager = KalypsoCorePlugin.getDefault()
            .getSelectionManager();

    public final StatusLineContributionItem m_statusBar = new StatusLineContributionItem("MapViewStatusBar", 100); //$NON-NLS-1$

    private IMapPanel m_mapPanel;

    private GisTemplateMapModell m_mapModell;

    private MapForm m_control;

    private boolean m_disposed = false;

    // TODO: this would also probably better made by a general map context: a general status line item that looks
    // for map context changes; it then always gets the current message from the map
    private final IMapPanelListener m_mapPanelListener = new MapPanelAdapter() {
        @Override
        public void onMessageChanged(final IMapPanel source, final String message) {
            final Display display = getSite().getShell().getDisplay();

            /* Update the text. */
            display.asyncExec(new Runnable() {
                @Override
                public void run() {
                    m_statusBar.setText(message);
                }
            });
        }
    };

    private GM_Envelope m_initialEnv;

    private BaseMapSchedulingRule m_baseMapSchedulingRule;

    protected AbstractMapPart() {
        super();
    }

    @Override
    public void init(final IEditorSite site, final IEditorInput input) {
        initMapPanel(site);

        super.init(site, input);
    }

    public void init(final IViewSite site) {
        setSite(site);

        initMapPanel(site);
    }

    private void initMapPanel(final IWorkbenchPartSite site) {
        final JobExclusiveCommandTarget commandTarget = getCommandTarget();

        m_statusBar.setText(""); //$NON-NLS-1$

        // both IViewSite und IEditorSite give access to actionBars
        final IActionBars actionBars = getActionBars(site);
        actionBars.getStatusLineManager().add(m_statusBar);
        actionBars.setGlobalActionHandler(ActionFactory.UNDO.getId(), commandTarget.undoAction);
        actionBars.setGlobalActionHandler(ActionFactory.REDO.getId(), commandTarget.redoAction);
        actionBars.updateActionBars();
    }

    @Override
    public synchronized void createPartControl(final Composite parent) {
        final IWorkbenchPartSite site = getSite();

        m_control = MapForm.createMapForm(parent);
        m_mapPanel = m_control.createMapPanel(this, m_selectionManager);

        updatePanel(m_mapModell, m_initialEnv);
        m_mapPanel.addMapPanelListener(m_mapPanelListener);

        final MapPanelSourceProvider sourceProvider = new MapPanelSourceProvider(site, m_mapPanel);
        setSourceProvider(sourceProvider);

        // REMARK: important: the map panel (awt) never gets the focus now. This fixes the following strange behavior,
        // - click into map
        // - click into other view -> view gets activated
        // - again click into map and than into other view -> view does not get activated, only the clicked control gets the focus.

        // Actually playing with focus and view activation did not solve this problem.

        // SOLUTION: is now: we keep the focus in our swt control and translate all swt key/mousewheel event manually to awt events
        // This will lead probably to some effects with the key events (so far testing did not show any strange behavior).
        // so TODO: the map-widgets should directly work with swt events instead; next step would be to incorporate the translation code
        // into the widget manager itself for backwards compatibility (i.e. introduce a new widget interface and make the old one deprecated).
        if (m_mapPanel instanceof MapPanel) {
            final MapPanel mapPanelComponent = (MapPanel) m_mapPanel;
            mapPanelComponent.addFocusListener(new FocusAdapter() {
                @Override
                public void focusGained(final java.awt.event.FocusEvent e) {
                    handleFocuesGained();
                }
            });

            m_control.addMouseWheelListener(new MapSwtWheelAdapter(mapPanelComponent));
            m_control.addKeyListener(new MapSwtKeyAdapter(mapPanelComponent));
        }

        // HACK: at the moment views never have a menu... maybe we could get the information,
        // if a context menu is desired from the defining extension
        if (this instanceof IEditorPart) {
            final MenuManager contextMenu = MapPartHelper.createMapContextMenu(m_control.getBody(), m_mapPanel,
                    site);
            ((IEditorSite) site).registerContextMenu(contextMenu, m_mapPanel, false);
        }

        site.setSelectionProvider(m_mapPanel);
    }

    protected void handleFocuesGained() {
        final IWorkbenchPartSite site = getSite();
        final IWorkbenchPage activePage = site.getWorkbenchWindow().getActivePage();

        final MapForm control = m_control;

        final Display display = site.getShell().getDisplay();
        display.asyncExec(new Runnable() {
            @Override
            public void run() {
                activePage.activate(AbstractMapPart.this);
                if (!control.isDisposed())
                    control.forceFocus();
            }
        });
    }

    @Override
    public void setFocus() {
        m_control.setFocus();
    }

    public IViewSite getViewSite() {
        return (IViewSite) getSite();
    }

    @Override
    protected synchronized void loadInternal(final IProgressMonitor monitor, final IStorageEditorInput input)
            throws CoreException {
        monitor.beginTask(Messages.getString("org.kalypso.ui.editor.mapeditor.AbstractMapPart.6"), 2); //$NON-NLS-1$

        try {
            // prepare for exception
            setMapModell(null, null);

            /* If no storage is passed, clear the map view. */
            if (input == null) {
                monitor.done();
                return;
            }

            /* "Loading map..." */
            if (m_mapPanel != null) {
                final String message = Messages.getString("org.kalypso.ui.editor.mapeditor.AbstractMapPart.1", //$NON-NLS-1$
                        input.getName()); //;
                m_control.setStatus(new Status(IStatus.INFO, KalypsoGisPlugin.getId(), message));
            }

            final Gismapview gisview = GisTemplateHelper.loadGisMapView(input.getStorage());
            monitor.worked(1);

            final URL context = findContext(input);

            if (!m_disposed) {
                final GM_Envelope env = GisTemplateHelper.getBoundingBox(gisview);
                final GisTemplateMapModell mapModell = new GisTemplateMapModell(context,
                        KalypsoDeegreePlugin.getDefault().getCoordinateSystem(), m_selectionManager);
                mapModell.createFromTemplate(gisview);
                setMapModell(mapModell, env);
            }
        } catch (final Throwable e) {
            e.printStackTrace();

            final IStatus status = StatusUtilities.statusFromThrowable(e);

            setMapModell(null, null);

            final IStatus error = new MultiStatus(KalypsoGisPlugin.getId(), -1, new IStatus[] { status },
                    Messages.getString("org.kalypso.ui.editor.mapeditor.AbstractMapPart.2"), null); //$NON-NLS-1$
            if (m_control != null)
                // FIXME: the control might not yet have been created, so this status is lost.
                // shouldn't we keep it ourselfs and set it to the control when created?
                m_control.setStatus(error);

            throw new CoreException(status);
        } finally {
            monitor.done();
        }
    }

    @Override
    public void showBusy(final boolean busy) {
        super.showBusy(busy);

        final Form control = m_control;
        if (control != null && !control.isDisposed()) {
            control.getDisplay().asyncExec(new Runnable() {
                @Override
                public void run() {
                    if (!control.isDisposed()) {
                        control.setBusy(false);
                    }
                }
            });
        }
    }

    public BaseMapSchedulingRule getSchedulingRule() {
        final IFile file;
        final IStorageEditorInput input = getEditorInput();
        if (input instanceof IFileEditorInput)
            file = ((IFileEditorInput) input).getFile();
        else
            file = null;

        return getSchedulingRule(m_mapPanel, file);
    }

    public synchronized BaseMapSchedulingRule getSchedulingRule(final IMapPanel mapPanel, final IFile file) {
        if (m_baseMapSchedulingRule != null) {
            final IResource oldMapFile = m_baseMapSchedulingRule.getMapFile();
            final IMapPanel oldMapPanel = m_baseMapSchedulingRule.getMapPanel();
            if (ObjectUtils.equals(oldMapFile, file) && oldMapPanel == mapPanel)
                return m_baseMapSchedulingRule;
        }

        m_baseMapSchedulingRule = new BaseMapSchedulingRule(mapPanel, file);
        return m_baseMapSchedulingRule;
    }

    @Override
    protected synchronized void doSaveInternal(final IProgressMonitor monitor, final IFile file)
            throws CoreException {
        if (m_mapModell == null)
            return;

        try {
            monitor.beginTask(Messages.getString("org.kalypso.ui.editor.mapeditor.AbstractMapPart.8"), 2000); //$NON-NLS-1$
            final GM_Envelope boundingBox = m_mapPanel.getBoundingBox();
            final String srsName = KalypsoDeegreePlugin.getDefault().getCoordinateSystem();
            m_mapModell.saveGismapTemplate(boundingBox, srsName, monitor, file);
        } catch (final CoreException e) {
            throw e;
        } catch (final Throwable e) {
            throw new CoreException(StatusUtilities.statusFromThrowable(e,
                    Messages.getString("org.kalypso.ui.editor.mapeditor.AbstractMapPart.9"))); //$NON-NLS-1$
        }
    }

    private void setMapModell(final GisTemplateMapModell mapModell, final GM_Envelope env) {
        if (m_mapModell != null && m_mapModell != mapModell)
            m_mapModell.dispose();

        m_mapModell = mapModell;
        m_initialEnv = env; // only needed, if mapPanel not yet available

        final String partName = getPartName(mapModell);

        // set as UI-Thread call to prevent the "invalid thread access" exception
        final Display display = getSite().getShell().getDisplay();
        display.asyncExec(new Runnable() {
            @Override
            public void run() {
                setPartName(partName);
            }
        });

        updatePanel(m_mapModell, m_initialEnv);
    }

    private String getPartName(final GisTemplateMapModell mapModell) {
        if (mapModell == null)
            return Messages.getString("org.kalypso.ui.editor.mapeditor.AbstractMapPart.11"); //$NON-NLS-1$

        final String label = mapModell.getLabel();
        if (label == null)
            return getEditorInput().getName();

        return label;
    }

    protected void updatePanel(final IKalypsoLayerModell mapModell, final GM_Envelope initialEnv) {
        if (m_mapPanel != null) {
            m_mapPanel.setMapModell(mapModell);
            if (initialEnv != null)
                m_mapPanel.setBoundingBox(initialEnv);
        }
    }

    public GisTemplateMapModell getMapModell() {
        return m_mapModell;
    }

    @Override
    public IMapPanel getMapPanel() {
        return m_mapPanel;
    }

    @Override
    public Object getAdapter(final Class adapter) {
        if (IExportableObjectFactory.class.equals(adapter))
            return new MapExportableObjectFactory(getMapPanel());

        if (IContentOutlinePage.class.equals(adapter)) {
            final GisMapOutlinePage page = new GisMapOutlinePage(getCommandTarget());
            page.setMapPanel(getMapPanel());
            return page;
        }

        if (adapter == IFile.class) {
            final IEditorInput input = getEditorInput();
            if (input instanceof IFileEditorInput)
                return ((IFileEditorInput) getEditorInput()).getFile();
        }

        if (adapter == IMapPanel.class)
            return m_mapPanel;

        if (adapter == Form.class)
            return m_control;

        return super.getAdapter(adapter);
    }

    @Override
    public void dispose() {
        m_disposed = true;

        setMapModell(null, null);

        m_mapPanel.dispose();

        super.dispose();
    }

    public void setStatusBarMessage(final String message) {
        m_statusBar.setText(message);
    }

    @Override
    public void setPartName(final String partName) {
        super.setPartName(partName);
    }
}