/******************************************************************************* * Copyright (c) 2012, 2014 Obeo. * 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: * Obeo - initial API and implementation *******************************************************************************/ package org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups; import static com.google.common.collect.Sets.newLinkedHashSet; import com.google.common.collect.Lists; import com.google.common.eventbus.EventBus; import java.util.List; import java.util.Set; import org.eclipse.emf.common.notify.Adapter; import org.eclipse.emf.common.notify.Notifier; import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.DifferenceGroupProviderChange; import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.EmptyDifferenceGroupProvider; import org.eclipse.emf.compare.rcp.ui.structuremergeviewer.groups.IDifferenceGroupProvider; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; /** * This class will be used by the EMF Compare UI to group differences together in the structural differences * tree viewer. * * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> * @since 4.0 */ public final class StructureMergeViewerGrouper { /** An empty difference group provider. */ private final IDifferenceGroupProvider empty; /** * The currently selected group provider. This is what will compute and give us the groups we need to * display. */ private IDifferenceGroupProvider provider; /** List of all TreeViewers on which this grouper is applied. */ private final List<StructuredViewer> viewers; /** The {@link EventBus} associated with this grouper. */ private final EventBus eventBus; /** The set of registered group provider that has been set on this grouper. */ private final Set<IDifferenceGroupProvider> registeredGroupProviders; /** * Constructs the difference grouper. * * @param eventBus * The {@link EventBus} which will be associated with this difference grouper. */ public StructureMergeViewerGrouper(EventBus eventBus) { this.empty = new EmptyDifferenceGroupProvider(); this.eventBus = eventBus; this.provider = empty; this.viewers = Lists.newArrayList(); this.registeredGroupProviders = newLinkedHashSet(); } /** * Sets the instance that will provide the groups to be displayed in the structural differences view. * * @param provider * The provider that will be use to compute the groups that are to be displayed in the UI. */ public void setProvider(IDifferenceGroupProvider provider) { if (this.provider != provider) { this.provider = provider; refreshViewers(); eventBus.post(new DifferenceGroupProviderChange(provider)); } } /** * Get the {@link IDifferenceGroupProvider} associated to this StructureMergeViewerGrouper. * * @return the provider associated to this StructureMergeViewerGrouper */ public IDifferenceGroupProvider getProvider() { return provider; } /** * Refreshes the viewers registered with this grouper. */ private void refreshViewers() { for (StructuredViewer viewer : viewers) { Adapter root = (Adapter)viewer.getInput(); if (root != null) { Notifier target = root.getTarget(); registerDifferenceGroupProvider(target, provider); } } } /** * Registers the selected IDifferenceGroupProvider to the given Notifier. * * @param notifier * the given Notifier. * @param groupProvider * the selected IDifferenceGroupProvider. */ protected void registerDifferenceGroupProvider(Notifier notifier, IDifferenceGroupProvider groupProvider) { List<Adapter> eAdapters = notifier.eAdapters(); Adapter oldGroupProvider = EcoreUtil.getAdapter(eAdapters, IDifferenceGroupProvider.class); if (oldGroupProvider != null) { eAdapters.remove(oldGroupProvider); } eAdapters.add(groupProvider); registeredGroupProviders.add(groupProvider); } /** * Install this grouper on the given viewer. * <p> * Note that this will also install a dispose listener on that viewer in order to remove the grouper * whenever the viewer is disposed. * </p> * * @param viewer * The viewer on which the grouper will be installed. */ public void install(final StructuredViewer viewer) { viewer.getControl().addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { uninstall(viewer); } }); viewers.add(viewer); } /** * Uninstall this grouper from the given viewer. * * @param viewer * The viewer from which the grouper should be removed. */ public void uninstall(StructuredViewer viewer) { Object input = viewer.getInput(); final Notifier notifier; if (input instanceof Notifier) { notifier = (Notifier)input; } else if (input instanceof Adapter) { notifier = ((Adapter)input).getTarget(); } else { notifier = null; } if (notifier != null) { List<Adapter> eAdapters = notifier.eAdapters(); Adapter groupProvider = EcoreUtil.getAdapter(eAdapters, IDifferenceGroupProvider.class); if (provider != groupProvider) { throw new IllegalStateException(); } eAdapters.remove(provider); } for (IDifferenceGroupProvider registeredGroupProvider : registeredGroupProviders) { registeredGroupProvider.dispose(); } viewers.remove(viewer); } }