/** * Copyright (C) 2014 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.refactoring.ui; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import org.bonitasoft.studio.common.Messages; import org.bonitasoft.studio.model.connectorconfiguration.ConnectorParameter; import org.bonitasoft.studio.model.process.Pool; import org.bonitasoft.studio.refactoring.core.RefactoringOperationType; import org.bonitasoft.studio.refactoring.core.script.ScriptContainer; import org.eclipse.compare.CompareConfiguration; import org.eclipse.compare.CompareEditorInput; import org.eclipse.compare.IContentChangeListener; import org.eclipse.compare.IContentChangeNotifier; import org.eclipse.compare.structuremergeviewer.DiffNode; import org.eclipse.compare.structuremergeviewer.DiffTreeViewer; import org.eclipse.compare.structuremergeviewer.Differencer; import org.eclipse.compare.structuremergeviewer.IDiffElement; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.edit.provider.ComposedAdapterFactory; import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; import org.eclipse.jface.viewers.IOpenListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.OpenEvent; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CLabel; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import com.google.common.base.Preconditions; public class BonitaCompareEditorInput extends CompareEditorInput { private DiffNode root = new DiffNode(Differencer.NO_CHANGE) { @Override public boolean hasChildren() { return true; } };; private DiffTreeViewer viewer; private final RefactoringOperationType operationType; private final String elementName; private final String newName; private boolean applyChanges = false; private boolean canBeContainedInScript = true; private final List<ScriptContainer<?>> scripts; private final AdapterFactoryLabelProvider adapterFactoryLabelProvider = new AdapterFactoryLabelProvider( new ComposedAdapterFactory( ComposedAdapterFactory.Descriptor.Registry.INSTANCE)); public BonitaCompareEditorInput(final CompareConfiguration configuration, final List<ScriptContainer<?>> scripts, final RefactoringOperationType operationType, final String elementName, final String newName, final boolean canBeContainedInScript) { super(configuration); this.scripts = scripts; this.elementName = elementName; this.operationType = operationType; this.newName = newName; this.canBeContainedInScript = canBeContainedInScript; } @Override protected Object prepareInput(final IProgressMonitor arg0) throws InvocationTargetException, InterruptedException { setDirty(true); if (!scripts.isEmpty()) { buildTree(); return root; } return null; } @Override public void setTitle(final String title) { if (operationType == RefactoringOperationType.UPDATE) { super.setTitle(Messages.bind(Messages.refactorTitle, elementName)); } else { super.setTitle(Messages.bind(Messages.removeTitle, elementName)); } } @Override public Control createContents(final Composite parent) { final CLabel label = new CLabel(parent, SWT.NONE); final String lastArgumentWithConditionOrNot = canBeContainedInScript ? " " + Messages.reviewChangesMessageWithConditionPlace : ""; if (operationType == RefactoringOperationType.UPDATE) { if (elementName.equals(newName)) { label.setText(Messages.bind(Messages.reviewTypeChangesMessageRefactoring, new String[] { elementName, lastArgumentWithConditionOrNot })); } else { label.setText(Messages.bind(Messages.reviewChangesMessageRefactoring, new String[] { elementName, newName, lastArgumentWithConditionOrNot })); } } else { label.setText(Messages.bind(Messages.reviewChangesMessageRemoving, elementName, lastArgumentWithConditionOrNot)); } label.setImage(Display.getCurrent().getSystemImage(SWT.ICON_WARNING)); return super.createContents(parent); } @Override public Viewer createDiffViewer(final Composite parent) { viewer = new DiffTreeViewer(parent, getCompareConfiguration()); viewer.addOpenListener(new IOpenListener() { @Override public void open(final OpenEvent event) { final IStructuredSelection sel = (IStructuredSelection) event.getSelection(); final DiffNode obj = (DiffNode) sel.getFirstElement(); obj.setDontExpand(false); } }); viewer.setFilters(getFilters()); viewer.setLabelProvider(new DiffTreeLabelProvider()); viewer.setContentProvider(new BonitaScriptRefactoringContentProvider()); viewer.setInput(root); viewer.expandAll(); return viewer; } @Override public String getTitle() { if (operationType == RefactoringOperationType.UPDATE) { return Messages.bind(Messages.refactorTitle, elementName); } else { return Messages.bind(Messages.removeTitle, elementName); } } public DiffTreeViewer getViewer() { return viewer; } public DiffNode getRoot() { return root; } public void setRoot(final DiffNode root) { this.root = root; } private ViewerFilter[] getFilters() { return new ViewerFilter[] { new ViewerFilter() { @Override public boolean select(final Viewer viewer, final Object parentElement, final Object element) { return true; } } }; } @Override public boolean canRunAsJob() { return true; } public void buildTree() { for (final ScriptContainer<?> script : scripts) { final LeftCompareScript left = new LeftCompareScript(script, adapterFactoryLabelProvider); final RightCompareScript right = new RightCompareScript(script, adapterFactoryLabelProvider); right.addContentChangeListener(new IContentChangeListener() { @Override public void contentChanged(final IContentChangeNotifier compareScript) { if (compareScript instanceof RightCompareScript) { setDirty(true); if (getViewer() == null || getViewer().getControl().isDisposed()) { return; } getViewer().refresh(true); } } }); final DiffNode leaf = new DiffNode(null, Differencer.CHANGE, null, left, right); final EObject eContainer = script.getModelElement().eContainer(); Preconditions.checkState(eContainer != null); final DiffNode poolNode = buildPathNodes(eContainer, leaf); if (((EObjectNode) poolNode.getAncestor()).getElement() instanceof Pool && root.getChildren().length == 0) { root.add(poolNode); } } } private DiffNode buildPathNodes(final EObject container, final DiffNode node) { final DiffNode parentNode = new DiffNode(Differencer.NO_CHANGE); node.setParent(parentNode); parentNode.add(node); final EObjectNode ancestor = new EObjectNode(container, adapterFactoryLabelProvider); parentNode.setAncestor(ancestor); if (insertParentNode(parentNode)) { return parentNode; } if (container instanceof Pool) { return parentNode; } if (container instanceof ConnectorParameter) { return buildPathNodes(container.eContainer().eContainer(), parentNode); } return buildPathNodes(container.eContainer(), parentNode); } private void getAllNodes(final List<DiffNode> nodes, final DiffNode root) { if (root.hasChildren()) { nodes.addAll((Collection<? extends DiffNode>) Arrays.asList(root.getChildren())); for (final IDiffElement child : root.getChildren()) { getAllNodes(nodes, (DiffNode) child); } } } private boolean insertParentNode(final DiffNode nodeToInsert) { final List<DiffNode> nodes = new ArrayList<DiffNode>(); getAllNodes(nodes, root); for (final DiffNode node : nodes) { if (node.getAncestor() != null && ((EObjectNode) node.getAncestor()).getElement() .equals(((EObjectNode) nodeToInsert.getAncestor()).getElement())) { addChildrenToParent(node, nodeToInsert.getChildren()); return true; } } return false; } private void addChildrenToParent(final DiffNode parent, final IDiffElement[] children) { for (final IDiffElement child : children) { parent.add(child); } } @Override public void saveChanges(final IProgressMonitor monitor) throws CoreException { super.saveChanges(monitor); applyChanges = true; } public boolean applyChanges() { return applyChanges; } @Override public boolean isDirty() { return true; } @Override public Object getCompareResult() { return super.getCompareResult(); } public void dispose() { adapterFactoryLabelProvider.dispose(); } }