org.kalypso.afgui.internal.TaskPerspectiveStore.java Source code

Java tutorial

Introduction

Here is the source code for org.kalypso.afgui.internal.TaskPerspectiveStore.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.afgui.internal;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProduct;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.ui.IPerspectiveDescriptor;
import org.eclipse.ui.IPerspectiveListener;
import org.eclipse.ui.IWindowListener;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PerspectiveAdapter;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.WorkbenchException;
import org.eclipse.ui.XMLMemento;
import org.eclipse.ui.internal.Perspective;
import org.eclipse.ui.internal.WorkbenchPage;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.WorkbenchWindow;
import org.eclipse.ui.internal.registry.PerspectiveDescriptor;
import org.eclipse.ui.internal.registry.PerspectiveRegistry;
import org.kalypso.afgui.KalypsoAFGUIFrameworkPlugin;
import org.kalypso.afgui.WorkflowHelper;
import org.osgi.framework.Version;

import com.google.common.base.Charsets;

import de.renew.workflow.base.ITask;
import de.renew.workflow.base.IWorkflow;

/**
 * This class is responsible for loading / storing the perspective configuration for a task.
 *
 * @author Gernot Belger
 */
@SuppressWarnings("restriction")
class TaskPerspectiveStore {
    private static final String USER_AREA_DIR = "taskPerspectives"; //$NON-NLS-1$

    /* Attribute name of root element that holds the version number added by Kalypso. */
    private static final String KEY_KALYPSO_VERISON = "kalypsoVersion"; //$NON-NLS-1$

    private final IWindowListener m_windowListener = new IWindowListener() {
        @Override
        public void windowOpened(final IWorkbenchWindow window) {
            handleWindowOpened(window);
        }

        @Override
        public void windowDeactivated(final IWorkbenchWindow window) {
        }

        @Override
        public void windowClosed(final IWorkbenchWindow window) {
            handleWindowClosed(window);
        }

        @Override
        public void windowActivated(final IWorkbenchWindow window) {
        }
    };

    private final IPerspectiveListener m_perspectiveListener = new PerspectiveAdapter() {
        @Override
        public void perspectiveChanged(final IWorkbenchPage page, final IPerspectiveDescriptor perspective,
                final String changeId) {
            if (IWorkbenchPage.CHANGE_RESET.equals(changeId))
                handlePerspectiveReset(perspective);
        }

        @Override
        public void perspectiveActivated(final IWorkbenchPage page, final IPerspectiveDescriptor perspective) {
            if (perspective.getId().equals(org.kalypso.afgui.perspective.Perspective.ID))
                handleWorkflowPerspectiveActivated();
        }

        @Override
        public void perspectivePreDeactivate(final IWorkbenchPage page, final IPerspectiveDescriptor perspective) {
            if (perspective.getId().equals(org.kalypso.afgui.perspective.Perspective.ID))
                handleWorkflowPerspectivePreDeactivate();
        }
    };

    private boolean m_resetInProgress = false;

    private final TaskExecutor m_executor;

    private boolean m_ignoreNextActivation = false;

    private boolean m_ignoreNextDeactivation = false;

    public TaskPerspectiveStore(final TaskExecutor executor) {
        m_executor = executor;

        final IWorkbench workbench = PlatformUI.getWorkbench();

        workbench.addWindowListener(m_windowListener);

        final IWorkbenchWindow[] workbenchWindows = workbench.getWorkbenchWindows();
        for (final IWorkbenchWindow window : workbenchWindows)
            handleWindowOpened(window);
    }

    /**
     * Returns the location of the perspective file in the system location for a given task; i.e. the pre-defined
     * perspective configuration, if any.
     */
    private XMLMemento loadSystemDefinition(final ITask task) {
        try {
            final URL systemLocation = getSystemLocation(task);

            try (Reader reader = new InputStreamReader(systemLocation.openStream(), Charsets.UTF_8)) {
                return XMLMemento.createReadRoot(reader);
            } catch (final IOException e) {
                // ignored, happens if file does not exist
                return null;
            } catch (final WorkbenchException e) {
                e.printStackTrace();
                return null;
            }
        } catch (final MalformedURLException e) {
            e.printStackTrace();
            return null;
        }
    }

    private URL getSystemLocation(final ITask task) throws MalformedURLException {
        if (task == null)
            return getClass().getResource("resources/no_task_persp.xml"); //$NON-NLS-1$

        final IWorkflow workflow = task.getWorkflow();
        final URL resourceContext = workflow.getResourceContext();

        final String filename = getFilename(task);

        return new URL(resourceContext, filename);
    }

    private XMLMemento loadUserDefinition(final ITask task) {
        if (task == null)
            return null;

        final File userFile = getUserFile(task);
        if (!userFile.exists())
            return null;

        try (Reader reader = new InputStreamReader(new FileInputStream(userFile), Charsets.UTF_8)) {
            return XMLMemento.createReadRoot(reader);
        } catch (IOException | WorkbenchException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * Returns the location of the perspective file in the user location for a given task.
     */
    private File getUserFile(final ITask task) {
        final File userDir = getUserArea();
        final String filename = getFilename(task);
        return new File(userDir, filename);
    }

    private String getFilename(final ITask task) {
        final String uri = task.getURI();
        return uri + "_persp.xml"; //$NON-NLS-1$
    }

    private File getUserArea() {
        final IPath stateLocation = KalypsoAFGUIFrameworkPlugin.getDefault().getStateLocation();
        final File stateDir = stateLocation.toFile();

        final File userAreaDir = new File(stateDir, USER_AREA_DIR);

        /* Create this directory */
        if (!userAreaDir.exists())
            userAreaDir.mkdir();

        return userAreaDir;
    }

    private Perspective getCurrentPerspective() {
        final IWorkbench workbench = PlatformUI.getWorkbench();
        final IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
        final WorkbenchPage page = (WorkbenchPage) window.getActivePage();
        if (page == null)
            return null;

        return page.getActivePerspective();
    }

    /**
     * Stores the current perspective settings under the name of the given task into the user area.
     */
    void saveTaskPerspective(final ITask task) {
        /* Never save empty task */
        if (task == null)
            return;

        /* Save current configuration to user file */
        final File taskPerspectiveFile = getUserFile(task);

        final Perspective perspective = getCurrentPerspective();
        if (perspective != null)
            savePerspective(perspective, taskPerspectiveFile);
    }

    private void savePerspective(final Perspective perspective, final File targetFile) {
        final XMLMemento memento = XMLMemento.createWriteRoot("perspective");//$NON-NLS-1$

        final String id = perspective.getDesc().getId();
        if (!org.kalypso.afgui.perspective.Perspective.ID.equals(id))
            return;

        /* Persist current state */
        final IStatus status = perspective.saveState(memento);
        if (!status.isOK()) {
            KalypsoAFGUIFrameworkPlugin.getDefault().getLog().log(status);
            return;
        }

        /* add Kalypso specific version information */
        final IProduct product = Platform.getProduct();
        final Version kalypsoVersion = product.getDefiningBundle().getVersion();
        memento.putString(KEY_KALYPSO_VERISON, kalypsoVersion.toString());

        try (final Writer writer = new OutputStreamWriter(new FileOutputStream(targetFile), Charsets.UTF_8)) {
            memento.save(writer);
        } catch (final IOException e) {
            e.printStackTrace();
        }
    }

    boolean restoreTaskPerspective(final ITask task) {
        final XMLMemento configuration = findDefinition(task);
        if (configuration == null)
            return false;

        try {
            final Perspective perspective = getCurrentPerspective();
            if (perspective != null)
                applyPerspectiveConfiguration(perspective, configuration);
            return true;
        } catch (final IOException e) {
            // will probably never happen, happens only if bundle store could not be written
            e.printStackTrace();
            return false;
        }
    }

    private XMLMemento findDefinition(final ITask task) {
        final XMLMemento systemDefinition = loadSystemDefinition(task);

        final XMLMemento userDefinition = loadUserDefinition(task);

        /* Fall back to system definition if no user definition exists yet */
        if (userDefinition == null)
            return systemDefinition;

        if (systemDefinition == null)
            return null;

        /* Both, user and system exist; chose the one which is more current */
        final Version systemVersion = getVersion(systemDefinition);
        final Version userVersion = getVersion(userDefinition);

        // TODO: check: what to do in the null case?
        /* Only use userDefinition if it is not outdated regarding its version number */
        if (systemVersion != null && systemVersion.compareTo(userVersion) <= 0)
            return userDefinition;

        return systemDefinition;
    }

    private Version getVersion(final XMLMemento definition) {
        final String versionText = definition.getString(KEY_KALYPSO_VERISON);
        if (StringUtils.isBlank(versionText))
            return null;

        try {
            return new Version(versionText);
        } catch (final IllegalArgumentException e) {
            e.printStackTrace();
            return null;
        }
    }

    private void applyPerspectiveConfiguration(final Perspective perspective, final XMLMemento memento)
            throws IOException {
        final PerspectiveRegistry registry = getPerspectiveRegistry();
        final PerspectiveDescriptor desc = (PerspectiveDescriptor) perspective.getDesc();

        if (!desc.getId().equals(org.kalypso.afgui.perspective.Perspective.ID))
            return;

        registry.saveCustomPersp(desc, memento);

        final IWorkbench workbench = PlatformUI.getWorkbench();
        final WorkbenchWindow window = (WorkbenchWindow) workbench.getActiveWorkbenchWindow();
        final WorkbenchPage page = (WorkbenchPage) window.getActivePage();

        m_resetInProgress = true;
        try {
            page.resetPerspective();
        } finally {
            m_resetInProgress = false;
        }
    }

    private PerspectiveRegistry getPerspectiveRegistry() {
        return (PerspectiveRegistry) WorkbenchPlugin.getDefault().getPerspectiveRegistry();
    }

    protected void handleWindowOpened(final IWorkbenchWindow window) {
        window.addPerspectiveListener(m_perspectiveListener);
    }

    protected void handleWindowClosed(final IWorkbenchWindow window) {
        window.removePerspectiveListener(m_perspectiveListener);
    }

    protected void handlePerspectiveReset(final IPerspectiveDescriptor perspective) {
        if (m_resetInProgress)
            return;

        if (!org.kalypso.afgui.perspective.Perspective.ID.equals(perspective.getId()))
            return;

        m_ignoreNextActivation = true;
        m_ignoreNextDeactivation = true;

        /* Delete user definition for the current task */
        final ITask activeTask = m_executor.getActiveTask();
        if (activeTask != null) {
            final File userFile = getUserFile(activeTask);
            FileUtils.deleteQuietly(userFile);
        }

        /* Reset definition for the active task */
        resetSystemSettings((PerspectiveDescriptor) perspective);
    }

    // TODO: not used, but this it how it is done; would be nice to have a menu to reset the whole definition
    void resetAll(final IPerspectiveDescriptor perspective) {
        if (m_resetInProgress)
            return;

        m_ignoreNextActivation = true;
        m_ignoreNextDeactivation = true;

        /* Delete all user definitions */
        clearUserEntries();

        /* Reset definition for the active task */
        resetSystemSettings((PerspectiveDescriptor) perspective);
    }

    private void clearUserEntries() {
        final File userDir = getUserArea();
        FileUtils.deleteQuietly(userDir);
    }

    private void resetSystemSettings(final PerspectiveDescriptor desc) {
        final ITask activeTask = WorkflowHelper.getActiveTask();
        final PerspectiveRegistry registry = getPerspectiveRegistry();

        final XMLMemento systemDefinition = loadSystemDefinition(activeTask);
        if (systemDefinition == null) {
            /* clear custom definition, so perspective is really reset from perspective factory */
            desc.revertToPredefined();
        } else {
            try {
                /* Reset to system definition */
                registry.saveCustomPersp(desc, systemDefinition);
            } catch (final IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Saves the layout for the currently active task. Necessary, because the user may close Kalypso after switching to
     * another perspective.
     */
    protected void handleWorkflowPerspectivePreDeactivate() {
        if (m_resetInProgress)
            return;

        if (m_ignoreNextDeactivation) {
            m_ignoreNextDeactivation = false;
            return;
        }

        final ITask activeTask = m_executor.getActiveTask();
        saveTaskPerspective(activeTask);
    }

    /**
     * Restores the perspective settings for currently the active task.<br/>
     * Necessary, because when a task is activated the perspective is sometimes not yet open.
     */
    protected void handleWorkflowPerspectiveActivated() {
        if (m_resetInProgress)
            return;

        if (m_ignoreNextActivation) {
            m_ignoreNextActivation = false;
            return;
        }

        final ITask activeTask = m_executor.getActiveTask();
        restoreTaskPerspective(activeTask);
    }
}