com.nokia.sdt.editor.EditorServices.java Source code

Java tutorial

Introduction

Here is the source code for com.nokia.sdt.editor.EditorServices.java

Source

/*
* Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/

package com.nokia.sdt.editor;

import com.nokia.sdt.datamodel.IDesignerDataModel;
import com.nokia.sdt.datamodel.IModelMessage;
import com.nokia.sdt.sourcegen.ISourceGenSession;
import com.nokia.sdt.uimodel.Messages;
import com.nokia.sdt.uimodel.UIModelPlugin;
import com.nokia.sdt.utils.IRunnableWithProgressAndStatus;
import com.nokia.cpp.internal.api.utils.core.*;
import com.nokia.cpp.internal.api.utils.ui.UITaskUtils;
import com.nokia.sdt.workspace.IDesignerDataModelSpecifier;
import com.nokia.sdt.workspace.WorkspaceContext;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.*;
import org.eclipse.jface.dialogs.*;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.*;
import org.eclipse.ui.ide.IDE;

import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.*;

public class EditorServices {

    public interface EditorListener {
        void editorAdded(IEditorPart editorPart);

        void editorRemoved(IEditorPart editorPart);
    }

    // Use LinkedHashSet to maintain editor ordering on revert
    private static Collection<IEditorPart> openEditors = new LinkedHashSet<IEditorPart>();
    private static Collection listeners;
    private static boolean stiflingProgress;

    public static void addEditor(IEditorPart editorPart) {
        synchronized (openEditors) {
            openEditors.add(editorPart);
            fireEditorAdded(editorPart);
        }
    }

    public static void removeEditor(IEditorPart editorPart) {
        synchronized (openEditors) {
            openEditors.remove(editorPart);
            fireEditorRemoved(editorPart);
        }
        WorkspaceContext.getContext().scheduleUnloadJob();
    }

    public static void saveAll(IProgressMonitor monitor) {
        synchronized (openEditors) {
            monitor.beginTask(Messages.getString("EditorServices.SavingAllModels"), //$NON-NLS-1$
                    openEditors.size());
            try {
                for (Iterator iter = openEditors.iterator(); iter.hasNext();) {
                    IEditorPart editor = (IEditorPart) iter.next();
                    editor.doSave(new SubProgressMonitor(monitor, 1));
                    if (monitor.isCanceled())
                        break;
                }
            } finally {
                monitor.done();
            }
        }
    }

    public static void saveAllModified(IProgressMonitor monitor) {
        synchronized (openEditors) {
            monitor.beginTask(Messages.getString("EditorServices.SavingAllModifiedModels"), //$NON-NLS-1$
                    openEditors.size());
            try {
                for (Iterator iter = openEditors.iterator(); iter.hasNext();) {
                    IEditorPart editor = (IEditorPart) iter.next();
                    if (editor.isDirty())
                        editor.doSave(new SubProgressMonitor(monitor, 1));
                    else
                        monitor.worked(1);
                    if (monitor.isCanceled())
                        break;
                }
            } finally {
                monitor.done();
            }
        }
    }

    public static void reloadAll(IProgressMonitor monitor) {
        // copy the editors list since opening/saving/reloading modifies it
        synchronized (openEditors) {
            Collection editors = new ArrayList(openEditors);
            monitor.beginTask(Messages.getString("EditorServices.ReloadingAllModels"), //$NON-NLS-1$
                    openEditors.size());
            try {
                // force the list to be empty and re-add ones that work so broken designs are flushed
                openEditors.clear();
                for (Iterator iter = editors.iterator(); iter.hasNext();) {
                    IDesignerDataModelEditor editor = (IDesignerDataModelEditor) iter.next();
                    editor.reload();
                    monitor.worked(1);
                    if (monitor.isCanceled())
                        break;
                }
            } finally {
                monitor.done();
            }
        }
    }

    public static IEditorPart findEditor(IDesignerDataModel dataModel) {
        synchronized (openEditors) {
            for (Iterator iter = openEditors.iterator(); iter.hasNext();) {
                IDesignerDataModelEditor editor = (IDesignerDataModelEditor) iter.next();
                IDesignerDataModel dm = editor.getDataModel();
                if ((dm != null) && dm.getModelSpecifier().equals(dataModel.getModelSpecifier()))
                    return (IEditorPart) editor.getAdapter(IEditorPart.class);
            }
            return null;
        }

    }

    /**
     * Save the editor 
     * @param editor a specific editor, or null for all open editors
     * @return true for success, false for failure
     */
    public static boolean saveEditor(final IEditorPart editor) {
        IRunnableWithProgress runnable = new IRunnableWithProgress() {
            public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                if (editor != null)
                    editor.doSave(monitor);
                else
                    EditorServices.saveAll(monitor);
            }
        };

        return UITaskUtils.runImmediately(runnable);
    }

    public synchronized static void addListener(EditorListener listener) {
        if (listeners == null)
            listeners = new ArrayList();

        if (!listeners.contains(listener))
            listeners.add(listener);
    }

    public synchronized static void removeListener(EditorListener listener) {
        if (listeners == null)
            return;

        listeners.remove(listener);
    }

    private synchronized static void fireEditorAdded(IEditorPart editorPart) {
        if (listeners == null)
            return;

        for (Iterator iter = (new ArrayList(listeners)).iterator(); iter.hasNext();) {
            EditorListener listener = (EditorListener) iter.next();
            listener.editorAdded(editorPart);
        }
    }

    private synchronized static void fireEditorRemoved(IEditorPart editorPart) {
        if (listeners == null)
            return;

        for (Iterator iter = (new ArrayList(listeners)).iterator(); iter.hasNext();) {
            EditorListener listener = (EditorListener) iter.next();
            listener.editorRemoved(editorPart);
        }
    }

    /**
     * Get an array of currently open editors.
     * @return array (copy) of editor parts 
     */
    public synchronized static IEditorPart[] getEditors() {
        return (IEditorPart[]) openEditors.toArray(new IEditorPart[openEditors.size()]);
    }

    /**
     * Return only the open editors with files in the given project
     * @param project
     */
    public synchronized static IDesignerDataModelEditor[] findEditorsForProject(IProject project) {
        if (project == null)
            return null;
        ArrayList<IDesignerDataModelEditor> result = new ArrayList<IDesignerDataModelEditor>();
        for (IEditorPart editorPart : openEditors) {
            if (editorPart instanceof IDesignerDataModelEditor) {
                IDesignerDataModelEditor ddme = (IDesignerDataModelEditor) editorPart;
                if (ddme.getDataModel() != null && ddme.getDataModel().getProjectContext() != null
                        && project == ddme.getDataModel().getProjectContext().getProject()) {
                    result.add(ddme);
                }
            }
        }
        return result.toArray(new IDesignerDataModelEditor[result.size()]);
    }

    public synchronized static IDesignerDataModelEditor findEditorForModel(
            IDesignerDataModelSpecifier modelSpecifier) {
        IDesignerDataModelEditor result = null;
        if (modelSpecifier != null) {
            for (IEditorPart editorPart : openEditors) {
                if (editorPart instanceof IDesignerDataModelEditor) {
                    IDesignerDataModelEditor ddme = (IDesignerDataModelEditor) editorPart;
                    if (modelSpecifier.equals(ddme.getDataModel().getModelSpecifier())) {
                        result = ddme;
                        break;
                    }
                }
            }
        }
        return result;
    }

    /**
     * Utility to save, with user confirmation, any of the given models that have open, 
     * dirty editors.
     * The API takes a list so it can use the Eclipse API to present the list of
     * dirty resources in a single dialog where appropriate. 
     * @param models collection of models to save
     * @return true if the save succeeded, false if the user canceled saving an affected editro
     */
    public synchronized static boolean confirmSaveDirtyModels(
            Collection<IDesignerDataModelSpecifier> modelSpecifiers) {

        // make a list of all editors onto these models, and a list of resources
        // for dirty editors only
        ArrayList<IDesignerDataModelEditor> editors = new ArrayList<IDesignerDataModelEditor>();
        ArrayList<IResource> dirtyModelResources = new ArrayList<IResource>();
        for (IDesignerDataModelSpecifier specifier : modelSpecifiers) {
            IDesignerDataModelEditor ddme = findEditorForModel(specifier);
            if (ddme != null) {
                editors.add(ddme);
                if (ddme.isDirty()) {
                    dirtyModelResources.add(specifier.getPrimaryResource());
                }
            }
        }
        boolean result = true;
        if (dirtyModelResources.size() > 0) {
            result = IDE.saveAllEditors(dirtyModelResources.toArray(new IResource[dirtyModelResources.size()]),
                    true);
        }
        return result;
    }

    /**
     * Utility to save a model, coordinating with any editor open
     * on the model.
     * @param model the model to save
     * @param monitor progress monitor to use, can be null
     * @return true if the save succeeded, false if the user canceled saving an affected editro
     */
    public synchronized static void saveModels(Collection<IDesignerDataModel> models, IProgressMonitor monitor)
            throws Exception {

        ArrayList<IDesignerDataModelEditor> editors = new ArrayList<IDesignerDataModelEditor>();
        for (IDesignerDataModel model : models) {
            IDesignerDataModelSpecifier specifier = model.getModelSpecifier();
            IDesignerDataModelEditor ddme = findEditorForModel(specifier);
            if (ddme != null) {
                editors.add(ddme);
                ddme.setListenToResourceChanges(false);
            }
        }

        if (monitor == null) {
            monitor = new NullProgressMonitor();
        }

        Exception caughtException = null;
        for (IDesignerDataModel model : models) {
            try {
                model.saveModel(monitor);
                notifyIfDataModelSourceGenProblems(null, model);
            } catch (Exception x) {
                caughtException = x;
            }
            if (caughtException != null) {
                break;
            }
        }

        for (IDesignerDataModelEditor ddme : editors) {
            ddme.setListenToResourceChanges(true);
            ddme.reload();
        }

        if (caughtException != null) {
            throw caughtException;
        }
    }

    /**
     * Tell whether any editors are open.  
     * @return true: yup, false: no way
     */
    public static boolean isAnyEditorOpen() {
        return openEditors.size() > 0;
    }

    /**
     * Override the automatic detection of whether to show a progress dialog.
     * @param stifle true: don't show progress
     */
    public static void setStifleProgress(boolean stifle) {
        stiflingProgress = stifle;
    }

    /**
     * Run a task, showing a progress dialog only when the workbench
     * is up and no editors are open, when we presume that load times 
     * will be much longer.
     * @param shell
     * @param runWithStatus
     * @return null for success, else IStatus for error
     */
    public static IStatus runWithProgressAndStatus(Shell shell,
            final IRunnableWithProgressAndStatus runWithStatus) {
        final IStatus status[] = { null };
        IRunnableWithProgress runnable = new IRunnableWithProgress() {
            public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                status[0] = runWithStatus.run(monitor);
            }
        };

        try {
            // the first load is likely to take long, so show a dialog in this case
            if (!stiflingProgress && !EditorServices.isAnyEditorOpen() && EditorServices.isEditorVisible(shell))
                new ProgressMonitorDialog(shell).run(false, false, runnable);
            else
                runnable.run(new NullProgressMonitor());

            if (status[0] == null || status[0] == Status.OK_STATUS)
                return null;
            else
                return status[0];
        } catch (Exception e) {
            return Logging.newStatus(UIModelPlugin.getDefault(), e);
        }

    }

    /**
     * Check whether the model's sourcegen session has reported any problems.
     * If so, show a dialog to alert the user.
     * @param shell
     * @param model
     */
    public static void notifyIfDataModelSourceGenProblems(Shell shell, IDesignerDataModel model) {
        if (!Platform.isRunning())
            return;

        ISourceGenSession session = model.getSourceGenSession();
        if (session == null)
            return;

        Collection<IMessage> messages = session.getMessages();
        boolean needToShow = false;

        // ignore info messages
        for (Iterator iter = messages.iterator(); iter.hasNext();) {
            IMessage message = (IMessage) iter.next();
            if (message.getSeverity() == IMessage.ERROR || message.getSeverity() == IMessage.WARNING) {
                needToShow = true;
                break;
            }
        }
        if (!needToShow)
            return;

        SourceGenProblemsDialog dialog = SourceGenProblemsDialog.create(shell,
                model.getModelSpecifier().getDisplayName(), session.getMessages());
        dialog.open();
    }

    /**
     * Tell whether the editor is visible, i.e. whether the given shell
     * is showing.  If null is passed, find whether any Eclipse window is visible.
     * @param shell the shell to test, or null for any Eclipse shell
     * @return
     */
    public static boolean isEditorVisible(Shell shell) {
        if (shell != null)
            return shell.isVisible();

        if (!Platform.isRunning())
            return false;

        final IWorkbench workbench;
        try {
            workbench = PlatformUI.getWorkbench();
        } catch (IllegalStateException e) {
            return false;
        }

        final IWorkbenchWindow[] activeWorkbenchWindow = { null };
        Display.getDefault().syncExec(new Runnable() {
            public void run() {
                activeWorkbenchWindow[0] = workbench.getActiveWorkbenchWindow();
            }
        });
        if (activeWorkbenchWindow[0] == null)
            return false;

        shell = activeWorkbenchWindow[0].getShell();
        if (shell == null)
            return false;

        return shell.isVisible();
    }

    /**
     * Create a dialog which reports model validation messages to the user.  
     * @param shell the shell, or null
     * @param model the model to mention
     * @param messages list of messages; if empty, the dialog is still created but it will not be shown on Dialog#open().
     * @return Dialog (never null)
     */
    public static Dialog createModelValidationMessagesDialog(Shell shell, IDesignerDataModel model,
            Collection<IModelMessage> messages) {
        // make mostly dummy IStatuses so we can use the way-cool error dialog
        List<IStatus> statusList = new ArrayList();
        for (Iterator iter = messages.iterator(); iter.hasNext();) {
            IModelMessage message = (IModelMessage) iter.next();
            String messageString = message.getMessage();
            String[] strings = messageString.split("\\n|\\r\\n");
            for (String string : strings) {
                statusList
                        .add(new Status(message.getSeverity(), UIModelPlugin.PLUGIN_ID, IStatus.OK, string, null));
            }
        }

        MultiStatus status = new MultiStatus(UIModelPlugin.PLUGIN_ID, IStatus.OK,
                (IStatus[]) statusList.toArray(new IStatus[statusList.size()]),
                MessageFormat.format(Messages.getString("EditorServices.ValidationProblemsText"), //$NON-NLS-1$
                        new Object[] { model.getModelSpecifier().getDisplayName() }),
                null);

        ErrorDialog dialog = new ErrorDialog(shell, Messages.getString("EditorServices.ValidationProblemsTitle"), //$NON-NLS-1$
                null, status, IStatus.ERROR | IStatus.WARNING);
        return dialog;
    }
}