org.bonitasoft.studio.properties.sections.general.ProcessElementNameContribution.java Source code

Java tutorial

Introduction

Here is the source code for org.bonitasoft.studio.properties.sections.general.ProcessElementNameContribution.java

Source

/**
 * Copyright (C) 2009-2015 Bonitasoft S.A.
 * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2.0 of the License, or
 * (at your option) any later version.
 * This program 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 General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.bonitasoft.studio.properties.sections.general;

import static org.bonitasoft.studio.common.jface.databinding.validator.ValidatorFactory.forbiddenCharactersValidator;
import static org.bonitasoft.studio.common.jface.databinding.validator.ValidatorFactory.minMaxLengthValidator;
import static org.bonitasoft.studio.common.jface.databinding.validator.ValidatorFactory.multiValidator;
import static org.bonitasoft.studio.common.jface.databinding.validator.ValidatorFactory.utf8InputValidator;

import java.lang.reflect.InvocationTargetException;
import java.util.List;

import org.bonitasoft.studio.common.diagram.Identifier;
import org.bonitasoft.studio.common.diagram.dialog.OpenNameAndVersionDialog;
import org.bonitasoft.studio.common.diagram.dialog.OpenNameAndVersionForDiagramDialog;
import org.bonitasoft.studio.common.diagram.dialog.ProcessesNameVersion;
import org.bonitasoft.studio.common.emf.tools.ExpressionHelper;
import org.bonitasoft.studio.common.emf.tools.ModelHelper;
import org.bonitasoft.studio.common.jface.databinding.validator.ValidatorFactory;
import org.bonitasoft.studio.common.log.BonitaStudioLog;
import org.bonitasoft.studio.common.properties.AbstractNamePropertySectionContribution;
import org.bonitasoft.studio.common.properties.ExtensibleGridPropertySection;
import org.bonitasoft.studio.common.repository.Repository;
import org.bonitasoft.studio.common.repository.RepositoryManager;
import org.bonitasoft.studio.diagram.custom.parts.CustomPoolEditPart;
import org.bonitasoft.studio.diagram.custom.refactoring.ProcessNamingTools;
import org.bonitasoft.studio.diagram.custom.repository.DiagramRepositoryStore;
import org.bonitasoft.studio.model.process.AbstractCatchMessageEvent;
import org.bonitasoft.studio.model.process.Element;
import org.bonitasoft.studio.model.process.Lane;
import org.bonitasoft.studio.model.process.MainProcess;
import org.bonitasoft.studio.model.process.Message;
import org.bonitasoft.studio.model.process.Pool;
import org.bonitasoft.studio.model.process.ProcessPackage;
import org.bonitasoft.studio.model.process.SequenceFlow;
import org.bonitasoft.studio.model.process.diagram.edit.parts.LaneEditPart;
import org.bonitasoft.studio.properties.i18n.Messages;
import org.bonitasoft.studio.properties.operation.RenameDiagramOperation;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.observable.value.IValueChangeListener;
import org.eclipse.core.databinding.observable.value.ValueChangeEvent;
import org.eclipse.core.databinding.validation.MultiValidator;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.databinding.EMFDataBindingContext;
import org.eclipse.emf.databinding.edit.EMFEditObservables;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.command.SetCommand;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gmf.runtime.diagram.core.listener.DiagramEventBroker;
import org.eclipse.gmf.runtime.diagram.core.listener.NotificationListener;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ITextAwareEditPart;
import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor;
import org.eclipse.jface.databinding.fieldassist.ControlDecorationSupport;
import org.eclipse.jface.databinding.swt.ISWTObservableValue;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.progress.IProgressService;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;

/**
 * @author Mickael Istria
 * @author Romain Bioteau
 */
public class ProcessElementNameContribution extends AbstractNamePropertySectionContribution {

    protected ISWTObservableValue observable;
    private UpdateValueStrategy labelModelToTargetUpdate;
    private UpdateValueStrategy labelTargetToModelUpdate;
    private boolean bindingInitialized = false;
    private ProcessNamingTools processNamingTools;

    private final NotificationListener updateMessage = new NotificationListener() {

        @Override
        public void notifyChanged(final Notification notification) {
            final List<AbstractCatchMessageEvent> messages = ModelHelper.getAllItemsOfType(element,
                    ProcessPackage.eINSTANCE.getAbstractCatchMessageEvent());
            for (final AbstractCatchMessageEvent m : messages) {
                final String eventName = m.getEvent();
                final Message event = ModelHelper.findEvent(ModelHelper.getMainProcess(element), eventName);
                if (event != null) {
                    editingDomain.getCommandStack().execute(SetCommand.create(editingDomain, event,
                            ProcessPackage.Literals.MESSAGE__TARGET_PROCESS_EXPRESSION,
                            ExpressionHelper.createConstantExpression(element.getName(), String.class.getName())));
                }
            }
        }
    };

    /**
     * @param tabbedPropertySheetPage
     * @param extensibleGridPropertySection
     */
    public ProcessElementNameContribution(final TabbedPropertySheetPage tabbedPropertySheetPage,
            final ExtensibleGridPropertySection extensibleGridPropertySection) {
        super(tabbedPropertySheetPage, extensibleGridPropertySection);
    }

    protected void updateEvents(final Element element) {
        for (final AbstractCatchMessageEvent ev : ModelHelper
                .getAllCatchEvent(ModelHelper.getMainProcess(element))) {
            final Message eventObject = ModelHelper.findEvent(element, ev.getEvent());
            if (eventObject != null) {
                editingDomain.getCommandStack().execute(new SetCommand(editingDomain, eventObject,
                        ProcessPackage.Literals.MESSAGE__TARGET_PROCESS_EXPRESSION,
                        ExpressionHelper.createConstantExpression(element.getName(), String.class.getName())));
            }
        }

    }

    /*
     * (non-Javadoc)
     * @seeorg.bonitasoft.studio.properties.sections.general.
     * IExtenstibleGridPropertySectionContribution#getLabel()
     */
    @Override
    public String getLabel() {
        return Messages.GeneralSection_Name;
    }

    /*
     * (non-Javadoc)
     * @seeorg.bonitasoft.studio.properties.sections.general.
     * IExtenstibleGridPropertySectionContribution
     * #setEObject(org.eclipse.emf.ecore.EObject)
     */
    @Override
    public void setEObject(final EObject object) {
        if (object instanceof Lane) {
            element = ModelHelper.getParentProcess(object);
        } else {
            element = (Element) object;
        }

        if (element instanceof MainProcess) {
            updateBindings();
        }

        if (element instanceof Pool) {
            activateNameListener();
        }

    }

    protected void activateNameListener() {
        if (editingDomain != null) {
            DiagramEventBroker.getInstance(editingDomain).addNotificationListener(element,
                    ProcessPackage.eINSTANCE.getElement_Name(), updateMessage);
        }
    }

    /*
     * (non-Javadoc)
     * @seeorg.bonitasoft.studio.properties.sections.general.
     * IExtenstibleGridPropertySectionContribution
     * #setSelection(org.eclipse.jface.viewers.ISelection)
     */
    @Override
    public void setSelection(final ISelection selection) {
        if (((StructuredSelection) selection).getFirstElement() instanceof LaneEditPart) {
            this.selection = new StructuredSelection(
                    ((LaneEditPart) ((StructuredSelection) selection).getFirstElement()).getParent());
        }
        this.selection = selection;
    }

    @Override
    public void setEditingDomain(final TransactionalEditingDomain editingDomain) {
        super.setEditingDomain(editingDomain);
        processNamingTools = new ProcessNamingTools(editingDomain);
    }

    private void updateBindings() {
        if (bindingInitialized) {
            if (text != null && !text.isDisposed()) {
                final int start = text.getSelection().x;
                context.dispose();
                context = new EMFDataBindingContext();
                context.bindValue(observable,
                        EMFEditObservables.observeValue(editingDomain, element,
                                ProcessPackage.Literals.ELEMENT__NAME),
                        labelTargetToModelUpdate, labelModelToTargetUpdate);
                text.setSelection(start);
            }
        }
    }

    /*
     * (non-Javadoc)
     * @see org.bonitasoft.studio.common.properties.IExtensibleGridPropertySectionContribution#dispose()
     */
    @Override
    public void dispose() {
        super.dispose();
        if (element instanceof Pool) {
            deactivateNameListener();
        }
    }

    protected void deactivateNameListener() {
        if (editingDomain != null) {
            DiagramEventBroker.getInstance(editingDomain).removeNotificationListener(element,
                    ProcessPackage.eINSTANCE.getElement_Name(), updateMessage);
        }
    }

    @Override
    protected void createBinding(final EMFDataBindingContext context) {
        observable = SWTObservables.observeDelayedValue(250, SWTObservables.observeText(text, SWT.Modify));

        final IObservableValue nameObservable = EMFEditObservables.observeValue(editingDomain, element,
                ProcessPackage.Literals.ELEMENT__NAME);
        nameObservable.addValueChangeListener(new IValueChangeListener() {

            @Override
            public void handleValueChange(final ValueChangeEvent event) {
                updatePropertyTabTitle();
                updatePartName((String) event.diff.getNewValue(), Display.getDefault());
            }
        });
        context.bindValue(observable, nameObservable);
        final MultiValidator validationStatusProvider = nameValidationStatusProvider(observable);
        context.addValidationStatusProvider(validationStatusProvider);
        ControlDecorationSupport.create(validationStatusProvider, SWT.LEFT);
        bindingInitialized = true;
    }

    protected MultiValidator nameValidationStatusProvider(final IObservableValue nameTextObservable) {
        return new MultiValidator() {

            @Override
            protected IStatus validate() {
                return multiValidator()
                        .addValidator(
                                minMaxLengthValidator(Messages.name, element instanceof SequenceFlow ? 0 : 1, 255))
                        .addValidator(utf8InputValidator(Messages.name))
                        .addValidator(forbiddenCharactersValidator(Messages.name, '#', '%', '$'))
                        .addValidator(ValidatorFactory.reservedRESTAPIKeywordsValidator()).create()
                        .validate(nameTextObservable.getValue());
            }
        };
    }

    protected void updatePartName(final String name, final Display display) {
        if (selection != null && !selection.isEmpty()) {
            final ITextAwareEditPart textAwareEditPart = getTextAwareEditPart((IStructuredSelection) selection);
            if (textAwareEditPart != null) {
                textAwareEditPart.setLabelText(name);
                display.asyncExec(refreshPoolEditPart(textAwareEditPart));
            }
        }
    }

    protected Runnable refreshPoolEditPart(final ITextAwareEditPart textAwareEditPart) {
        return new Runnable() {

            @Override
            public void run() {
                final EditPart poolEp = getPoolEditPart(textAwareEditPart);
                if (poolEp != null) {
                    poolEp.refresh();
                }
            }
        };
    }

    protected EditPart getPoolEditPart(final EditPart textAwareEditPart) {
        EditPart poolEp = textAwareEditPart;
        while (poolEp != null && !(poolEp instanceof CustomPoolEditPart)) {
            if (poolEp.getParent() instanceof EditPart) {
                poolEp = poolEp.getParent();
            } else {
                poolEp = null;
            }
        }
        return poolEp;
    }

    protected ITextAwareEditPart getTextAwareEditPart(final IStructuredSelection selection) {
        final Object ep = selection.getFirstElement();
        ITextAwareEditPart textAwareEditPart = null;
        if (ep instanceof IGraphicalEditPart
                && element.equals(((IGraphicalEditPart) ep).resolveSemanticElement())) {
            if (ep instanceof ITextAwareEditPart) {
                textAwareEditPart = (ITextAwareEditPart) ep;
            }
            for (final Object child : ((IGraphicalEditPart) ep).getChildren()) {
                if (child instanceof ITextAwareEditPart) {
                    textAwareEditPart = (ITextAwareEditPart) child;
                }
            }
        }
        return textAwareEditPart;
    }

    @Override
    protected void editProcessNameAndVersion() {
        if (element instanceof Pool) {
            editSinglePoolNameAndVersion((Pool) element);
        } else {
            editDiagramAndPoolNameAndVersion();
        }
    }

    protected void editDiagramAndPoolNameAndVersion() {
        final MainProcess diagram = ModelHelper.getMainProcess(element);
        final DiagramRepositoryStore diagramStore = RepositoryManager.getInstance()
                .getRepositoryStore(DiagramRepositoryStore.class);
        final OpenNameAndVersionForDiagramDialog nameDialog = new OpenNameAndVersionForDiagramDialog(
                Display.getDefault().getActiveShell(), diagram, diagramStore);
        if (nameDialog.open() == Dialog.OK) {
            final DiagramEditor editor = (DiagramEditor) PlatformUI.getWorkbench().getActiveWorkbenchWindow()
                    .getActivePage().getActiveEditor();
            final MainProcess newProcess = (MainProcess) editor.getDiagramEditPart().resolveSemanticElement();
            editingDomain.getCommandStack().execute(SetCommand.create(editingDomain, newProcess,
                    ProcessPackage.Literals.ABSTRACT_PROCESS__AUTHOR, System.getProperty("user.name", "Unknown")));
            final String oldName = newProcess.getName();
            final String oldVersion = newProcess.getVersion();
            if (new Identifier(oldName, oldVersion).equals(nameDialog.getIdentifier())) {
                renamePoolsOnly(nameDialog, editor, newProcess);
            } else {
                renameDiagramAndPool(nameDialog, editor, newProcess);
            }
        }
    }

    protected void renameDiagramAndPool(final OpenNameAndVersionForDiagramDialog nameDialog,
            final DiagramEditor editor, final MainProcess newProcess) {
        final RenameDiagramOperation renameDiagramOperation = new RenameDiagramOperation();
        final Identifier identifier = nameDialog.getIdentifier();
        renameDiagramOperation.setDiagramToDuplicate(newProcess);
        renameDiagramOperation.setNewDiagramName(identifier.getName());
        renameDiagramOperation.setNewDiagramVersion(identifier.getVersion());
        renameDiagramOperation.setPoolsRenamed(nameDialog.getPools());
        renameDiagramOperation.setEditor(editor);
        final IProgressService service = PlatformUI.getWorkbench().getProgressService();
        try {
            service.run(false, false, renameDiagramOperation);
        } catch (final InvocationTargetException e) {
            BonitaStudioLog.error(e);
        } catch (final InterruptedException e) {
            BonitaStudioLog.error(e);
        }
    }

    protected void editSinglePoolNameAndVersion(final Pool pool) {
        final DiagramRepositoryStore diagramStore = RepositoryManager.getInstance()
                .getRepositoryStore(DiagramRepositoryStore.class);
        final OpenNameAndVersionDialog dialog1 = new OpenNameAndVersionDialog(Display.getDefault().getActiveShell(),
                pool, diagramStore);
        if (dialog1.open() == Dialog.OK) {
            final String oldPoolName = element.getName();
            final String oldVersion = ((Pool) element).getVersion();
            final Identifier identifier = dialog1.getIdentifier();
            processNamingTools.proceedForPools(element, identifier.getName(), oldPoolName, oldVersion,
                    identifier.getVersion());
        }
    }

    protected void renamePoolsOnly(final OpenNameAndVersionForDiagramDialog nameDialog, final DiagramEditor editor,
            final MainProcess newProcess) {
        editor.doSave(Repository.NULL_PROGRESS_MONITOR);
        final Identifier identifier = nameDialog.getIdentifier();
        processNamingTools.changeProcessNameAndVersion(newProcess, identifier.getName(), identifier.getVersion());
        for (final ProcessesNameVersion pnv : nameDialog.getPools()) {
            processNamingTools.changeProcessNameAndVersion(pnv.getAbstractProcess(), pnv.getNewName(),
                    pnv.getNewVersion());
        }
        try {
            final ICommandService service = (ICommandService) PlatformUI.getWorkbench()
                    .getService(ICommandService.class);
            final org.eclipse.core.commands.Command c = service.getCommand("org.eclipse.ui.file.save");
            if (c.isEnabled()) {
                c.executeWithChecks(new ExecutionEvent());
            }
        } catch (final Exception e) {
            BonitaStudioLog.error(e);
        }
    }

}