| /******************************************************************************* |
| * Copyright (c) 2008-2011 Chair for Applied Software Engineering, |
| * Technische Universitaet Muenchen. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| ******************************************************************************/ |
| package org.eclipse.emf.emfstore.client.ui.dialogs.merge; |
| |
| import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isAttribute; |
| import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isComposite; |
| import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isCompositeRef; |
| import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isDelete; |
| import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isDiagramLayout; |
| import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isMultiAtt; |
| import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isMultiAttMove; |
| import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isMultiAttSet; |
| import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isMultiRef; |
| import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isMultiRefSet; |
| import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isSingleRef; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.ListIterator; |
| import java.util.Set; |
| |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.Conflict; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.AttributeConflict; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.CompositeConflict; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.DeletionConflict; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.DiagramLayoutConflict; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiAttributeConflict; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiAttributeMoveConflict; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiAttributeMoveSetConflict; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiAttributeSetConflict; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiAttributeSetSetConflict; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiReferenceConflict; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiReferenceSetConflict; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiReferenceSetSetConflict; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiReferenceSetSingleConflict; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiReferenceSingleConflict; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.ReferenceConflict; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.SingleReferenceConflict; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.util.DecisionUtil; |
| import org.eclipse.emf.emfstore.client.ui.dialogs.merge.util.EventLogger; |
| import org.eclipse.emf.emfstore.client.ui.views.changes.ChangePackageVisualizationHelper; |
| import org.eclipse.emf.emfstore.common.model.ModelElementId; |
| import org.eclipse.emf.emfstore.common.model.Project; |
| import org.eclipse.emf.emfstore.common.model.util.ModelUtil; |
| import org.eclipse.emf.emfstore.server.conflictDetection.ConflictDetector; |
| import org.eclipse.emf.emfstore.server.model.versioning.ChangePackage; |
| import org.eclipse.emf.emfstore.server.model.versioning.LogMessage; |
| import org.eclipse.emf.emfstore.server.model.versioning.PrimaryVersionSpec; |
| import org.eclipse.emf.emfstore.server.model.versioning.operations.AbstractOperation; |
| import org.eclipse.emf.emfstore.server.model.versioning.operations.CompositeOperation; |
| import org.eclipse.emf.emfstore.server.model.versioning.operations.CreateDeleteOperation; |
| import org.eclipse.emf.emfstore.server.model.versioning.operations.MultiAttributeOperation; |
| import org.eclipse.emf.emfstore.server.model.versioning.operations.MultiReferenceOperation; |
| |
| /** |
| * DecisionManager is the controller for the merge dialog and therefore it's main component. It calculates the conflicts |
| * from incoming changes and can execute resolved conflicts. |
| * |
| * @author wesendon |
| */ |
| public class DecisionManager { |
| |
| private final Project project; |
| private final ChangePackage myChangePackage; |
| private final List<ChangePackage> theirChangePackages; |
| private ConflictDetector conflictDetector; |
| |
| private ArrayList<Conflict> conflicts; |
| private ArrayList<AbstractOperation> notInvolvedInConflict; |
| private ArrayList<AbstractOperation> acceptedMine; |
| private ArrayList<AbstractOperation> rejectedTheirs; |
| private final PrimaryVersionSpec baseVersion; |
| private final PrimaryVersionSpec targetVersion; |
| private ChangePackageVisualizationHelper visualizationHelper; |
| private EventLogger eventLogger; |
| |
| /** |
| * Default constructor. |
| * |
| * @param project the related project |
| * @param myChangePackage my changes |
| * @param theirChangePackages incoming changes |
| * @param baseVersion baseversion |
| * @param targetVersion new target version |
| */ |
| public DecisionManager(Project project, ChangePackage myChangePackage, List<ChangePackage> theirChangePackages, |
| PrimaryVersionSpec baseVersion, PrimaryVersionSpec targetVersion) { |
| this.project = project; |
| this.myChangePackage = myChangePackage; |
| this.theirChangePackages = theirChangePackages; |
| this.baseVersion = baseVersion; |
| this.targetVersion = targetVersion; |
| conflictDetector = new ConflictDetector(); |
| init(); |
| getEventLogger() |
| .createMergeEvent(baseVersion, targetVersion, conflicts.size(), myChangePackage.getOperations()); |
| } |
| |
| private void init() { |
| // flatten operations |
| List<AbstractOperation> myOperations = myChangePackage.getOperations(); |
| List<AbstractOperation> theirOperations = new ArrayList<AbstractOperation>(); |
| for (ChangePackage cp : theirChangePackages) { |
| theirOperations.addAll(cp.getOperations()); |
| } |
| |
| acceptedMine = new ArrayList<AbstractOperation>(); |
| rejectedTheirs = new ArrayList<AbstractOperation>(); |
| notInvolvedInConflict = new ArrayList<AbstractOperation>(); |
| |
| conflicts = new ArrayList<Conflict>(); |
| ArrayList<Conflicting> conflicting = new ArrayList<Conflicting>(); |
| |
| // Collect all conflicting |
| ListIterator<AbstractOperation> myIterator = myOperations.listIterator(myOperations.size()); |
| while (myIterator.hasPrevious()) { |
| AbstractOperation myOperation = myIterator.previous(); |
| boolean involved = false; |
| ListIterator<AbstractOperation> theirIterator = theirOperations.listIterator(theirOperations.size()); |
| while (theirIterator.hasPrevious()) { |
| AbstractOperation theirOperation = theirIterator.previous(); |
| if (conflictDetector.doConflict(myOperation, theirOperation)) { |
| involved = true; |
| boolean conflictingYet = false; |
| List<Conflicting> tmpConf = new ArrayList<Conflicting>(); |
| // check against conflicting |
| for (Conflicting conf : conflicting) { |
| if (conf.add(myOperation, theirOperation)) { |
| tmpConf.add(conf); |
| conflictingYet = true; |
| } |
| } |
| // merge conflicting |
| if (tmpConf.size() > 1) { |
| Conflicting main = tmpConf.get(0); |
| for (int i = 1; i < tmpConf.size(); i++) { |
| Conflicting conf = tmpConf.get(i); |
| main.addMyOps(conf.getMyOperations()); |
| main.addTheirOps(conf.getTheirOperations()); |
| conflicting.remove(conf); |
| } |
| } |
| if (!conflictingYet) { |
| conflicting.add(new Conflicting(myOperation, theirOperation)); |
| } |
| } |
| } |
| if (!involved) { |
| notInvolvedInConflict.add(myOperation); |
| } |
| } |
| |
| createConflicts(conflicting); |
| } |
| |
| /** |
| * BEGIN FACTORY TODO EXTRACT FACTORY CLASS. |
| */ |
| |
| // BEGIN COMPLEX CODE |
| private void createConflicts(ArrayList<Conflicting> conflicting) { |
| // Create Conflicts from Conflicting |
| for (Conflicting conf : conflicting) { |
| AbstractOperation my = conf.getMyOperation(); |
| AbstractOperation their = conf.getTheirOperation(); |
| |
| if (isDiagramLayout(my) && isDiagramLayout(their)) { |
| |
| addConflict(createDiagramLayoutDecision(conf)); |
| continue; |
| |
| } else if (isAttribute(my) && isAttribute(their)) { |
| |
| addConflict(createAttributeAttributeDecision(conf)); |
| continue; |
| |
| } else if (isSingleRef(my) && isSingleRef(their)) { |
| |
| addConflict(createSingleSingleConflict(conf)); |
| continue; |
| |
| } else if (isMultiRef(my) && isMultiRef(their)) { |
| |
| addConflict(createMultiMultiConflict(conf)); |
| continue; |
| |
| } else if ((isMultiRef(my) && isSingleRef(their)) || (isMultiRef(their) && isSingleRef(my))) { |
| |
| addConflict(createMultiSingle(conf)); |
| continue; |
| |
| } else if (isCompositeRef(my) && isCompositeRef(their)) { |
| |
| addConflict(createReferenceConflict(conf)); |
| continue; |
| |
| } else if ((isCompositeRef(my) && (isMultiRef(their) || isSingleRef(their))) |
| || ((isMultiRef(my) || isSingleRef(my)) && isCompositeRef(their))) { |
| |
| addConflict(createReferenceCompVSSingleMulti(conf)); |
| continue; |
| |
| } else if ((isMultiRef(my) && isMultiRefSet(their)) || (isMultiRef(their) && isMultiRefSet(my))) { |
| |
| addConflict(createMultiRefMultiSet(conf)); |
| continue; |
| |
| } else if (isMultiRefSet(my) && isMultiRefSet(their)) { |
| |
| addConflict(createMultiRefSetSet(conf)); |
| continue; |
| |
| } else if ((isMultiRefSet(my) && isSingleRef(their)) || (isMultiRefSet(their) && isSingleRef(my))) { |
| |
| addConflict(createMultiSetSingle(conf)); |
| continue; |
| |
| } else if (isMultiAtt(my) && isMultiAtt(their)) { |
| |
| addConflict(createMultiAtt(conf)); |
| continue; |
| |
| } else if ((isMultiAtt(my) && isMultiAttSet(their)) || (isMultiAtt(their) && isMultiAttSet(my))) { |
| |
| addConflict(createMultiAttSet(conf)); |
| continue; |
| |
| } else if ((isMultiAtt(my) && isMultiAttMove(their)) || (isMultiAtt(their) && isMultiAttMove(my))) { |
| |
| addConflict(createMultiAttMove(conf)); |
| continue; |
| |
| } else if ((isMultiAttSet(my) && isMultiAttMove(their)) || (isMultiAttSet(their) && isMultiAttMove(my))) { |
| |
| addConflict(createMultiAttMoveSet(conf)); |
| continue; |
| |
| } else if (isMultiAttSet(my) && isMultiAttSet(their)) { |
| |
| addConflict(createMultiAttSetSet(conf)); |
| continue; |
| |
| } else if (isComposite(my) || isComposite(their)) { |
| |
| addConflict(createCompositeConflict(conf)); |
| continue; |
| |
| } else if (isDelete(my) || isDelete(their)) { |
| |
| addConflict(createDeleteOtherConflict(conf)); |
| |
| } |
| } |
| } |
| |
| private void addConflict(Conflict conflict) { |
| if (conflict == null) { |
| return; |
| } |
| conflicts.add(conflict); |
| } |
| |
| // END COMPLEX CODE |
| private Conflict createMultiRefMultiSet(Conflicting conf) { |
| if (isMultiRef(conf.getMyOperation())) { |
| return new MultiReferenceSetConflict(conf.getMyOperations(), conf.getTheirOperations(), this, true); |
| } else { |
| return new MultiReferenceSetConflict(conf.getTheirOperations(), conf.getMyOperations(), this, false); |
| } |
| } |
| |
| private Conflict createMultiSetSingle(Conflicting conf) { |
| if (isMultiRefSet(conf.getMyOperation())) { |
| return new MultiReferenceSetSingleConflict(conf.getMyOperations(), conf.getTheirOperations(), this, true); |
| } else { |
| return new MultiReferenceSetSingleConflict(conf.getTheirOperations(), conf.getMyOperations(), this, false); |
| } |
| } |
| |
| private Conflict createMultiSingle(Conflicting conf) { |
| if (isMultiRef(conf.getMyOperation())) { |
| return new MultiReferenceSingleConflict(conf.getMyOperations(), conf.getTheirOperations(), this, true); |
| } else { |
| return new MultiReferenceSingleConflict(conf.getTheirOperations(), conf.getMyOperations(), this, false); |
| } |
| } |
| |
| private Conflict createMultiRefSetSet(Conflicting conf) { |
| return new MultiReferenceSetSetConflict(conf.getMyOperations(), conf.getTheirOperations(), this); |
| } |
| |
| private Conflict createMultiAttSetSet(Conflicting conf) { |
| return new MultiAttributeSetSetConflict(conf.getMyOperations(), conf.getTheirOperations(), this); |
| } |
| |
| private Conflict createMultiAtt(Conflicting conf) { |
| if (((MultiAttributeOperation) conf.getMyOperation()).isAdd()) { |
| return new MultiAttributeConflict(conf.getMyOperations(), conf.getTheirOperations(), this, true); |
| } else { |
| return new MultiAttributeConflict(conf.getTheirOperations(), conf.getMyOperations(), this, false); |
| |
| } |
| } |
| |
| private Conflict createMultiAttSet(Conflicting conf) { |
| if (isMultiAtt(conf.getMyOperation())) { |
| return new MultiAttributeSetConflict(conf.getMyOperations(), conf.getTheirOperations(), this, true); |
| } else { |
| return new MultiAttributeSetConflict(conf.getTheirOperations(), conf.getMyOperations(), this, false); |
| } |
| } |
| |
| private Conflict createMultiAttMove(Conflicting conf) { |
| if (isMultiAtt(conf.getMyOperation())) { |
| return new MultiAttributeMoveConflict(conf.getMyOperations(), conf.getTheirOperations(), this, true); |
| } else { |
| return new MultiAttributeMoveConflict(conf.getTheirOperations(), conf.getMyOperations(), this, false); |
| } |
| } |
| |
| private Conflict createMultiAttMoveSet(Conflicting conf) { |
| if (isMultiAttSet(conf.getMyOperation())) { |
| return new MultiAttributeMoveSetConflict(conf.getMyOperations(), conf.getTheirOperations(), this, true); |
| } else { |
| return new MultiAttributeMoveSetConflict(conf.getTheirOperations(), conf.getMyOperations(), this, false); |
| } |
| } |
| |
| private Conflict createReferenceCompVSSingleMulti(Conflicting conf) { |
| if (isCompositeRef(conf.getMyOperation())) { |
| return createRefFromSub(conf, ((CompositeOperation) conf.getMyOperation()).getSubOperations(), |
| Arrays.asList(conf.getTheirOperation())); |
| } else { |
| return createRefFromSub(conf, Arrays.asList(conf.getMyOperation()), |
| ((CompositeOperation) conf.getTheirOperation()).getSubOperations()); |
| } |
| } |
| |
| private Conflict createReferenceConflict(Conflicting conf) { |
| EList<AbstractOperation> myOperations = ((CompositeOperation) conf.getMyOperation()).getSubOperations(); |
| EList<AbstractOperation> theirOperations = ((CompositeOperation) conf.getTheirOperation()).getSubOperations(); |
| |
| return createRefFromSub(conf, myOperations, theirOperations); |
| } |
| |
| private Conflict createRefFromSub(Conflicting conf, List<AbstractOperation> myOperations, |
| List<AbstractOperation> theirOperations) { |
| |
| for (AbstractOperation myOp : myOperations) { |
| for (AbstractOperation theirOp : theirOperations) { |
| if (conflictDetector.doConflict(myOp, theirOp)) { |
| if (isSingleRef(myOp)) { |
| |
| return new ReferenceConflict(createSingleSingleConflict(myOp, theirOp), conf.getMyOperations(), |
| conf.getTheirOperations()); |
| |
| } else if (isMultiRef(myOp)) { |
| |
| return new ReferenceConflict(createMultiMultiConflict(myOp, theirOp), conf.getMyOperations(), |
| conf.getTheirOperations()); |
| |
| } else { |
| return null; |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| private Conflict createAttributeAttributeDecision(Conflicting conflicting) { |
| return new AttributeConflict(conflicting.getMyOperations(), conflicting.getTheirOperations(), this); |
| } |
| |
| private Conflict createDiagramLayoutDecision(Conflicting conflicting) { |
| return new DiagramLayoutConflict(conflicting.getMyOperations(), conflicting.getTheirOperations(), this); |
| } |
| |
| private Conflict createSingleSingleConflict(Conflicting conflicting) { |
| return new SingleReferenceConflict(conflicting.getMyOperations(), conflicting.getTheirOperations(), this); |
| } |
| |
| private Conflict createSingleSingleConflict(AbstractOperation my, AbstractOperation their) { |
| return new SingleReferenceConflict(Arrays.asList(my), Arrays.asList(their), this); |
| } |
| |
| private Conflict createMultiMultiConflict(Conflicting conf) { |
| if (((MultiReferenceOperation) conf.getMyOperation()).isAdd()) { |
| return new MultiReferenceConflict(conf.getMyOperations(), conf.getTheirOperations(), this, true); |
| } else { |
| return new MultiReferenceConflict(conf.getMyOperations(), conf.getTheirOperations(), this, false); |
| } |
| } |
| |
| private Conflict createMultiMultiConflict(AbstractOperation my, AbstractOperation their) { |
| if (((MultiReferenceOperation) my).isAdd()) { |
| return new MultiReferenceConflict(Arrays.asList(my), Arrays.asList(their), this, true); |
| } else { |
| return new MultiReferenceConflict(Arrays.asList(their), Arrays.asList(my), this, false); |
| } |
| } |
| |
| private Conflict createDeleteOtherConflict(Conflicting conf) { |
| if (isDelete(conf.getMyOperation())) { |
| return new DeletionConflict(conf.getMyOperations(), conf.getTheirOperations(), true, this); |
| } else { |
| return new DeletionConflict(conf.getTheirOperations(), conf.getMyOperations(), false, this); |
| } |
| } |
| |
| private Conflict createCompositeConflict(Conflicting conf) { |
| if (isComposite(conf.getMyOperation())) { |
| return new CompositeConflict(conf.getMyOperations(), conf.getTheirOperations(), this, true); |
| } else { |
| return new CompositeConflict(conf.getTheirOperations(), conf.getMyOperations(), this, false); |
| } |
| } |
| |
| /** |
| * FACTORY END |
| */ |
| |
| /** |
| * Returns the conflicts. |
| * |
| * @return list of conflicts. |
| */ |
| public ArrayList<Conflict> getConflicts() { |
| return conflicts; |
| } |
| |
| /** |
| * Checks whether all conflicts are resolved. |
| * |
| * @return true if all are resolved |
| */ |
| public boolean isResolved() { |
| boolean isResolved = true; |
| for (Conflict conflict : conflicts) { |
| isResolved = isResolved && conflict.isResolved(); |
| } |
| return isResolved; |
| } |
| |
| /** |
| * Get "my" accepted operations. This list will be empty, if {@link #calcResult()} hasn't been called before. |
| * |
| * @return list of operations |
| */ |
| public List<AbstractOperation> getAcceptedMine() { |
| return acceptedMine; |
| } |
| |
| /** |
| * Get "their" accepted operations. This list will be empty, if {@link #calcResult()} hasn't been called before. |
| * |
| * @return list of operations |
| */ |
| public List<AbstractOperation> getRejectedTheirs() { |
| return rejectedTheirs; |
| } |
| |
| /** |
| * If all conflicts are resolved this method will generate the resulting operations from the conflicts. Then call |
| * {@link #getAcceptedMine()} and {@link #getRejectedTheirs()}. |
| */ |
| public void calcResult() { |
| if (!isResolved()) { |
| return; |
| } |
| // collect my acknowledge operations |
| for (AbstractOperation myOp : myChangePackage.getOperations()) { |
| if (notInvolvedInConflict.contains(myOp)) { |
| acceptedMine.add(myOp); |
| } else { |
| for (Conflict conflict : conflicts) { |
| if (conflict.getAcceptedMine().contains(myOp)) { |
| acceptedMine.add(myOp); |
| } |
| } |
| } |
| } |
| |
| // Collect other accepted, which were generated in the merge process |
| for (Conflict conflict : conflicts) { |
| for (AbstractOperation ao : conflict.getAcceptedMine()) { |
| if (!acceptedMine.contains(ao)) { |
| acceptedMine.add(ao); |
| } |
| } |
| } |
| |
| for (ChangePackage theirCP : theirChangePackages) { |
| for (AbstractOperation theirOp : theirCP.getOperations()) { |
| for (Conflict conflict : conflicts) { |
| if (conflict.getRejectedTheirs().contains(theirOp)) { |
| rejectedTheirs.add(theirOp); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Returns the conflictdetector. |
| * |
| * @return conflictdetector |
| */ |
| public ConflictDetector getConflictDetector() { |
| return conflictDetector; |
| } |
| |
| /** |
| * Get the Name of an model element by modelelement id. |
| * |
| * @param modelElementId id of element |
| * @return name as string |
| */ |
| public String getModelElementName(ModelElementId modelElementId) { |
| return getModelElementName(getModelElement(modelElementId)); |
| } |
| |
| /** |
| * Get the Name of an model element. |
| * |
| * @param modelElement element |
| * @return name as string |
| */ |
| public String getModelElementName(EObject modelElement) { |
| AdapterFactoryLabelProvider adapterFactory = DecisionUtil.getAdapterFactory(); |
| return adapterFactory.getText(modelElement); |
| } |
| |
| /** |
| * Returns the modelelement. Therefore the project as well as creation and deletion operations are searched. |
| * |
| * @param modelElementId id of element. |
| * @return modelelement |
| */ |
| public EObject getModelElement(ModelElementId modelElementId) { |
| EObject modelElement = project.getModelElement(modelElementId); |
| if (modelElement == null) { |
| modelElement = searchForCreatedME(modelElementId, myChangePackage.getOperations()); |
| if (modelElement == null) { |
| for (ChangePackage cp : theirChangePackages) { |
| modelElement = searchForCreatedME(modelElementId, cp.getOperations()); |
| if (modelElement != null) { |
| break; |
| } |
| } |
| } |
| } |
| return modelElement; |
| } |
| |
| private EObject searchForCreatedME(ModelElementId modelElementId, List<AbstractOperation> operations) { |
| for (AbstractOperation operation : operations) { |
| EObject result = null; |
| if (operation instanceof CreateDeleteOperation) { |
| result = searchCreateAndDelete((CreateDeleteOperation) operation, modelElementId); |
| |
| } else if (operation instanceof CompositeOperation) { |
| EList<AbstractOperation> subOperations = ((CompositeOperation) operation).getSubOperations(); |
| result = searchForCreatedME(modelElementId, subOperations); |
| } else { |
| continue; |
| } |
| if (result != null) { |
| return result; |
| } |
| } |
| return null; |
| } |
| |
| private EObject searchCreateAndDelete(CreateDeleteOperation cdo, ModelElementId modelElementId) { |
| EObject modelElement = cdo.getModelElement(); |
| if (modelElement == null) { |
| return null; |
| } |
| Set<EObject> containedModelElements = ModelUtil.getAllContainedModelElements(modelElement, false); |
| containedModelElements.add(modelElement); |
| |
| for (EObject child : containedModelElements) { |
| ModelElementId childId = ModelUtil.clone(cdo.getEObjectToIdMap().get(child)); |
| if (child != null && childId.equals(modelElementId)) { |
| return child; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the name of the author for a operation in list of their operations. |
| * |
| * @param theirOperation operation |
| * @return name as string or "" |
| */ |
| public String getAuthorForOperation(AbstractOperation theirOperation) { |
| for (ChangePackage cp : theirChangePackages) { |
| for (AbstractOperation op : cp.getOperations()) { |
| List<AbstractOperation> tmpList = new ArrayList<AbstractOperation>(); |
| if (op instanceof CompositeOperation) { |
| tmpList.add(op); |
| tmpList.addAll(((CompositeOperation) op).getSubOperations()); |
| } else { |
| tmpList.add(op); |
| } |
| for (AbstractOperation ao : tmpList) { |
| if (ao.equals(theirOperation)) { |
| LogMessage log = cp.getLogMessage(); |
| if (log == null) { |
| return ""; |
| } |
| return (log.getAuthor() == null) ? "" : log.getAuthor(); |
| |
| } |
| } |
| } |
| } |
| return ""; |
| } |
| |
| /** |
| * Return the related project. |
| * |
| * @return project |
| */ |
| public Project getProject() { |
| return project; |
| } |
| |
| /** |
| * Returns the visualizationhelper. |
| * |
| * @return visualizationhelper |
| */ |
| public ChangePackageVisualizationHelper getChangePackageVisualizationHelper() { |
| if (visualizationHelper == null) { |
| ArrayList<ChangePackage> list = new ArrayList<ChangePackage>(); |
| list.add(myChangePackage); |
| list.addAll(theirChangePackages); |
| visualizationHelper = new ChangePackageVisualizationHelper(list, project); |
| } |
| return visualizationHelper; |
| } |
| |
| /** |
| * Return the Eventlogger. |
| * |
| * @return logger |
| */ |
| public EventLogger getEventLogger() { |
| if (eventLogger == null) { |
| eventLogger = new EventLogger(project); |
| } |
| return eventLogger; |
| } |
| |
| /** |
| * Returns the baseVersion of the project which is updating. |
| * |
| * @return version |
| */ |
| public PrimaryVersionSpec getBaseVersion() { |
| return baseVersion; |
| } |
| |
| /** |
| * Returns the targetVersion of the update which caused merging. |
| * |
| * @return version |
| */ |
| public PrimaryVersionSpec getTargetVersion() { |
| return targetVersion; |
| } |
| |
| /** |
| * Container for connected, conflicting operations. |
| * |
| * @author wesendon |
| */ |
| private class Conflicting { |
| |
| private ArrayList<AbstractOperation> myOps; |
| private ArrayList<AbstractOperation> theirOps; |
| |
| public Conflicting(AbstractOperation myOp, AbstractOperation theirOp) { |
| myOps = new ArrayList<AbstractOperation>(); |
| myOps.add(myOp); |
| theirOps = new ArrayList<AbstractOperation>(); |
| theirOps.add(theirOp); |
| } |
| |
| public AbstractOperation getTheirOperation() { |
| return theirOps.get(0); |
| } |
| |
| public AbstractOperation getMyOperation() { |
| return myOps.get(0); |
| } |
| |
| public List<AbstractOperation> getTheirOperations() { |
| return theirOps; |
| } |
| |
| public List<AbstractOperation> getMyOperations() { |
| return myOps; |
| } |
| |
| public boolean add(AbstractOperation myOp, AbstractOperation theirOp) { |
| for (AbstractOperation ao : getTheirOperations()) { |
| if (conflictDetector.doConflict(myOp, ao)) { |
| addToList(myOp, theirOp); |
| return true; |
| } |
| } |
| for (AbstractOperation ao : getMyOperations()) { |
| if (conflictDetector.doConflict(ao, theirOp)) { |
| addToList(myOp, theirOp); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private void addToList(AbstractOperation my, AbstractOperation their) { |
| addMyOp(my); |
| addTheirOp(their); |
| } |
| |
| private void addMyOp(AbstractOperation my) { |
| if (!myOps.contains(my)) { |
| myOps.add(my); |
| } |
| } |
| |
| private void addTheirOp(AbstractOperation their) { |
| if (!theirOps.contains(their)) { |
| theirOps.add(their); |
| } |
| } |
| |
| public void addMyOps(List<AbstractOperation> ops) { |
| for (AbstractOperation ao : ops) { |
| addMyOp(ao); |
| } |
| } |
| |
| public void addTheirOps(List<AbstractOperation> ops) { |
| for (AbstractOperation ao : ops) { |
| addTheirOp(ao); |
| } |
| } |
| } |
| } |