/******************************************************************************* * Copyright (c) 2006-2009 * Software Technology Group, Dresden University of Technology * * 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: * Software Technology Group - TU Dresden, Germany * - initial API and implementation ******************************************************************************/ package org.reuseware.coconut.roundtrip.impl; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.reuseware.coconut.roundtrip.RoundTripAdapter; import org.reuseware.coconut.roundtrip.EModificationType; import org.reuseware.coconut.roundtrip.ICallbackCopyFragment; import org.reuseware.coconut.roundtrip.ICallbackFragmentSelected; import org.reuseware.coconut.roundtrip.IConflictResolver; /** * AddHandler extends AbstractHandler to implement analysis functionality for * modifications that add elements. * * @author Roland Samlaus */ public class AddHandler extends AbstractHandler { public AddHandler(IConflictResolver resolver) { super(resolver); } /** * Handle the addition of an element. The addition may cause conflicts, * if the fragment is used in multiple composition programs. If this is * the case, the conflict resolver is asked for a resolution. * * @param modifiedFragmentUFI * the UFI of the modified fragment * @param adapter * The adapter that was notified after adding an element. */ public void handleAdd(URI modifiedFragmentUFI, RoundTripAdapter adapter) { // first check whether the addition can possibly be // propagated to multiple source fragments and use // conflict resolver to choose one Set<URI> otherEdgeUFIs = getNeigbourUFIs(adapter, adapter.getOriginalUFI()); if (otherEdgeUFIs.size() > 1) { selectSourceFragment(modifiedFragmentUFI, otherEdgeUFIs, adapter); } else if (otherEdgeUFIs.size() == 1) { // found single UFI checkForMultipleCompositionPrograms(otherEdgeUFIs.iterator().next(), adapter); } else { assert false; } } /** * Checks whether the element was added "on edge". If so, the element can be * added to multiple source fragments. * * @param adapter * CopiedFromAdapter that was notified. * @param ufi * UFI of the fragment where the element was added. * @return List of possible source fragment UFIs. */ private Set<URI> getNeigbourUFIs(RoundTripAdapter adapter, URI ufi) { // has the parent a different UFI? Set<URI> otherUFIs = new LinkedHashSet<URI>(); otherUFIs.add(ufi); List<EObject> neighbours = adapter.getCopyValues(); for (EObject neighbour : neighbours) { RoundTripAdapter cfAdapter = getAdapter(neighbour); if (cfAdapter == null) { continue; } Resource resource = cfAdapter.getOriginal().eResource(); if (resource == null) { continue; } URI otherUFI = resource.getURI(); otherUFIs.add(otherUFI); } return otherUFIs; } public void confirmChanges(RoundTripAdapter adapter) { adapter.confirmAddElements(); } public void discardChanges(RoundTripAdapter adapter) { adapter.discardAdd(); } /* private void postCompareAction(CopiedFromAdapter adapter) { adapter.undoChanges(); } private void preCompareAction(CopiedFromAdapter adapter) { adapter.addTemporary(); } */ /** * Asks the conflict resolve to choose one of the possible source fragments * when the new element can be potentially added. * * @param modifiedFragmentUFI * the UFIs of the modified fragment * @param sourceUFIs * the UFIs of all possible source fragments * @param adapter * the adapter that was notified about the addition of a new element */ private void selectSourceFragment( final URI modifiedFragmentUFI, Set<URI> sourceUFIs, RoundTripAdapter adapter) { getConflictResolver().chooseSourceFragement(EModificationType.ON_EDGE, sourceUFIs, adapter, new ICallbackFragmentSelected() { public void fragmentSelected(RoundTripAdapter adapter, URI selectedFragmentUFI) { RoundTripAdapter newAdapter = tranferChangeToSelectedFragment(adapter, selectedFragmentUFI); checkForMultipleCompositionPrograms(selectedFragmentUFI, newAdapter); } }); } private void checkForMultipleCompositionPrograms(URI modifiedSourceFragmentUFI, RoundTripAdapter adapter) { // the check whether the modified source fragment is // used in multiple composition programs List<URI> compositionProgramUFIs = getCompositionProgramsUsing(modifiedSourceFragmentUFI); if (compositionProgramUFIs.size() == 1) { confirmChanges(adapter); } else if (compositionProgramUFIs.size() > 1) { getConflictResolver().chooseCopyFragement(EModificationType.ADD, compositionProgramUFIs, adapter, new ICallbackCopyFragment() { public void copySelected(boolean doCopy, RoundTripAdapter adapter) { if (doCopy) { copyFragment(adapter); } else { confirmChanges(adapter); } } }); } else { assert false; } } @Override public void modifyTemporary(RoundTripAdapter adapter) { adapter.addTemporary(); } private RoundTripAdapter tranferChangeToSelectedFragment( RoundTripAdapter adapter, URI selectedFragmentUFI) { List<EObject> copies = adapter.getCopyValues(); for (EObject copy : copies) { RoundTripAdapter copyAdapter = getAdapter(copy); if (copyAdapter == null) { continue; } Resource resource = copyAdapter.getOriginal().eResource(); if (resource == null) { continue; } // find the adapter for the element in the selected // fragment if (resource.getURI().equals(selectedFragmentUFI)) { copyAdapter.setCopyValues(adapter.getCopyValues()); copyAdapter.setFeature(adapter.getFeature()); copyAdapter.setIdx(adapter.getIdx()); copyAdapter.setOriginal(copyAdapter.getOriginal().eContainer()); return copyAdapter; } } return adapter; } }