/** * <copyright> * * Copyright (c) 2017 Thales Global Services S.A.S. * 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: * Thales Global Services S.A.S. - initial API and implementation * * </copyright> */ package org.eclipse.emf.diffmerge.ui.specification.ext; import java.util.ArrayList; import java.util.List; import org.eclipse.emf.common.command.BasicCommandStack; import org.eclipse.emf.common.notify.Adapter; import org.eclipse.emf.common.notify.AdapterFactory; import org.eclipse.emf.diffmerge.api.Role; import org.eclipse.emf.diffmerge.ui.EMFDiffMergeUIPlugin; import org.eclipse.emf.diffmerge.ui.specification.IComparisonMethod; import org.eclipse.emf.diffmerge.ui.util.MiscUtil; import org.eclipse.emf.diffmerge.ui.viewers.AbstractComparisonViewer; import org.eclipse.emf.diffmerge.ui.viewers.ComparisonViewer; import org.eclipse.emf.ecore.provider.EcoreItemProviderAdapterFactory; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.util.ECrossReferenceAdapter; import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain; import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.emf.edit.provider.ComposedAdapterFactory; import org.eclipse.emf.edit.provider.IDisposable; import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory; import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.IActionBars; /** * A base implementation of IComparisonMethod. * @author Olivier Constant */ public abstract class AbstractComparisonMethod implements IComparisonMethod { /** Whether the comparison method has been fully initialized */ private boolean _initialized; /** The (initially null) editing domain */ private EditingDomain _editingDomain; /** Whether the editing domain in which the comparison takes place, if any, is entirely dedicated to the comparison */ protected boolean _isDedicatedEditingDomain; /** * Constructor */ protected AbstractComparisonMethod() { _editingDomain = null; _isDedicatedEditingDomain = false; _initialized = false; } /** * Clear the given resource set * @param resourceSet_p a non-null object */ protected void clearResourceSet(ResourceSet resourceSet_p) { List<Resource> resources = new ArrayList<Resource>(resourceSet_p.getResources()); for (Resource resource : resources) { for (Adapter adapter : new ArrayList<Adapter>(resource.eAdapters())) { if (adapter instanceof ECrossReferenceAdapter) resource.eAdapters().remove(adapter); } } for (Resource resource : resources) { try { if (resource.isLoaded()) resource.unload(); resourceSet_p.getResources().remove(resource); } catch (Exception e) { // Proceed } } } /** * @see org.eclipse.emf.diffmerge.ui.specification.IComparisonMethod#configure() */ public void configure() { // Override for configurable comparison methods } /** * @see org.eclipse.emf.diffmerge.ui.specification.IComparisonMethod#createComparisonViewer(org.eclipse.swt.widgets.Composite, org.eclipse.ui.IActionBars) */ public AbstractComparisonViewer createComparisonViewer(Composite parent_p, IActionBars actionBars_p) { ComparisonViewer result = doCreateComparisonViewer(parent_p, actionBars_p); ILabelProvider customLP = getCustomLabelProvider(); if (customLP != null) result.setDelegateLabelProvider(customLP); return result; } /** * Create and return an editing domain that is dedicated to the comparison * @return a non-null editing domain */ protected EditingDomain createEditingDomain() { // Override for custom editing domain ComposedAdapterFactory adapterFactory = new ComposedAdapterFactory( ComposedAdapterFactory.Descriptor.Registry.INSTANCE); adapterFactory.addAdapterFactory(new ResourceItemProviderAdapterFactory()); adapterFactory.addAdapterFactory(new EcoreItemProviderAdapterFactory()); adapterFactory.addAdapterFactory(new ReflectiveItemProviderAdapterFactory()); return new AdapterFactoryEditingDomain(adapterFactory, new BasicCommandStack()); } /** * Dispose this comparison method. * This excludes scopes, comparison and Eclipse operation history. * @see org.eclipse.emf.edit.provider.IDisposable#dispose() */ public void dispose() { final EditingDomain domain = getEditingDomain(); if (domain != null && _isDedicatedEditingDomain) { // Dedicated editing domain: clear it entirely // (useful if comparison computation was cancelled) MiscUtil.executeAndForget(domain, new Runnable() { /** * @see java.lang.Runnable#run() */ public void run() { clearResourceSet(domain.getResourceSet()); } }); domain.getCommandStack().flush(); } // Domain is empty: dispose adapter factories if (domain instanceof AdapterFactoryEditingDomain && domain.getResourceSet().getResources().isEmpty()) { AdapterFactoryEditingDomain afed = (AdapterFactoryEditingDomain)domain; AdapterFactory af = afed.getAdapterFactory(); if (af instanceof IDisposable) ((IDisposable)af).dispose(); } // Dedicated transactional editing domain: dispose it if (domain instanceof TransactionalEditingDomain && _isDedicatedEditingDomain) ((TransactionalEditingDomain)domain).dispose(); // Also clean shared adapter factory: icons associated to resources AdapterFactory af = EMFDiffMergeUIPlugin.getDefault().getAdapterFactoryLabelProvider().getAdapterFactory(); if (af instanceof ComposedAdapterFactory) { ComposedAdapterFactory composed = (ComposedAdapterFactory)af; AdapterFactory afForType = composed.getFactoryForType(Resource.class.getPackage()); if (afForType instanceof ResourceItemProviderAdapterFactory) { ResourceItemProviderAdapterFactory ripaf = (ResourceItemProviderAdapterFactory)afForType; ripaf.dispose(); } } } /** * Create and return the viewer for the comparison. * Its label provider can be customized separately. * @param parent_p a non-null composite * @param actionBars_p an optional IActionBars, typically for contributing global actions * such as undo/redo */ protected ComparisonViewer doCreateComparisonViewer(Composite parent_p, IActionBars actionBars_p) { return new ComparisonViewer(parent_p, actionBars_p); } /** * Get the editing domain for this comparison (this method is only called once) * @return a potentially null editing domain */ protected EditingDomain doGetEditingDomain() { // By default, create a dedicated editing domain _isDedicatedEditingDomain = true; return createEditingDomain(); } /** * Return an optional label provider for customizing the way model elements * are represented in comparison widgets. The client is responsible for disposing * the label provider when appropriate. * @return a label provider, or null for the default label provider */ protected ILabelProvider getCustomLabelProvider() { return null; } /** * @see org.eclipse.emf.edit.domain.IEditingDomainProvider#getEditingDomain() */ public final EditingDomain getEditingDomain() { // By default, try to obtain an editing domain if not initialized if (!_initialized) { _editingDomain = doGetEditingDomain(); _initialized = true; } return _editingDomain; } /** * @see org.eclipse.emf.diffmerge.ui.specification.IComparisonMethod#getResourceSet(org.eclipse.emf.diffmerge.api.Role) */ public ResourceSet getResourceSet(Role role_p) { return null; } /** * @see org.eclipse.emf.diffmerge.ui.specification.IComparisonMethod#isConfigurable() */ public boolean isConfigurable() { return false; } /** * @see org.eclipse.emf.diffmerge.ui.specification.IComparisonMethod#isThreeWay() */ public boolean isThreeWay() { return getModelScopeDefinition(Role.ANCESTOR) != null; } }