blob: f94946d2fb8a706e7ca6566ec0bd4b71144686ca [file] [log] [blame]
/*
* Copyright (c) 2015 Eike Stepper (Berlin, Germany) and others.
* 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:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.emf.cdo.explorer.ui.checkouts;
import org.eclipse.emf.cdo.CDOElement;
import org.eclipse.emf.cdo.CDOObject;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.revision.CDOList;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.CDORevisionManager;
import org.eclipse.emf.cdo.eresource.CDOResourceFolder;
import org.eclipse.emf.cdo.eresource.CDOResourceNode;
import org.eclipse.emf.cdo.explorer.CDOExplorerManager;
import org.eclipse.emf.cdo.explorer.CDOExplorerManager.ElementsChangedEvent;
import org.eclipse.emf.cdo.explorer.CDOExplorerUtil;
import org.eclipse.emf.cdo.explorer.checkouts.CDOCheckout;
import org.eclipse.emf.cdo.explorer.checkouts.CDOCheckoutManager;
import org.eclipse.emf.cdo.explorer.checkouts.CDOCheckoutManager.CheckoutStateEvent;
import org.eclipse.emf.cdo.explorer.ui.ViewerUtil;
import org.eclipse.emf.cdo.explorer.ui.bundle.OM;
import org.eclipse.emf.cdo.explorer.ui.checkouts.actions.OpenWithActionProvider;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionCache;
import org.eclipse.emf.cdo.ui.CDOItemProvider;
import org.eclipse.emf.cdo.util.CDOUtil;
import org.eclipse.emf.cdo.view.CDOView;
import org.eclipse.net4j.util.container.IContainerEvent;
import org.eclipse.net4j.util.event.IEvent;
import org.eclipse.net4j.util.event.IListener;
import org.eclipse.net4j.util.lifecycle.LifecycleException;
import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
import org.eclipse.net4j.util.ui.UIUtil;
import org.eclipse.net4j.util.ui.views.ItemProvider;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.ITreeItemContentProvider;
import org.eclipse.emf.edit.provider.ItemProviderAdapter;
import org.eclipse.emf.spi.cdo.InternalCDOObject;
import org.eclipse.emf.spi.cdo.InternalCDOView;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.navigator.CommonViewer;
import org.eclipse.ui.navigator.ICommonContentExtensionSite;
import org.eclipse.ui.navigator.ICommonContentProvider;
import org.eclipse.ui.part.IPage;
import org.eclipse.ui.views.properties.IPropertySource;
import org.eclipse.ui.views.properties.IPropertySourceProvider;
import org.eclipse.ui.views.properties.PropertySheet;
import org.eclipse.ui.views.properties.PropertySheetPage;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Eike Stepper
*/
public class CDOCheckoutContentProvider implements ICommonContentProvider, IPropertySourceProvider, IOpenListener
{
private static final Map<String, CDOCheckoutContentProvider> INSTANCES = new HashMap<String, CDOCheckoutContentProvider>();
private static final Set<Object> LOADING_OBJECTS = new HashSet<Object>();
private static final Method GET_CHILDREN_FEATURES_METHOD = getMethod(ItemProviderAdapter.class, "getChildrenFeatures",
Object.class);
private static final Method FIND_ITEM_METHOD = getMethod(StructuredViewer.class, "findItem", Object.class);
private static final CDOCheckoutManager CHECKOUT_MANAGER = CDOExplorerUtil.getCheckoutManager();
private final IListener checkoutManagerListener = new IListener()
{
public void notifyEvent(IEvent event)
{
CDOCheckoutViewerRefresh viewerRefresh = stateManager.getViewerRefresh();
if (event instanceof IContainerEvent)
{
viewerRefresh.addNotification(null, true, true);
}
else if (event instanceof CheckoutStateEvent)
{
CheckoutStateEvent e = (CheckoutStateEvent)event;
CDOCheckout checkout = e.getCheckout();
CDOCheckout.State state = e.getNewState();
if (state == CDOCheckout.State.Opening)
{
// Trigger hasChildren().
ViewerUtil.refresh(viewer, checkout);
// Trigger getChildren().
ViewerUtil.expand(viewer, checkout, true);
}
else
{
if (state == CDOCheckout.State.Closed)
{
ViewerUtil.expand(viewer, checkout, false);
}
viewerRefresh.addNotification(checkout, true, true);
if (state == CDOCheckout.State.Open)
{
ViewerUtil.expand(viewer, checkout, true);
}
updatePropertySheetPage(checkout);
}
}
else if (event instanceof CDOExplorerManager.ElementsChangedEvent)
{
CDOExplorerManager.ElementsChangedEvent e = (CDOExplorerManager.ElementsChangedEvent)event;
ElementsChangedEvent.StructuralImpact structuralImpact = e.getStructuralImpact();
Object[] changedElements = e.getChangedElements();
if (structuralImpact != ElementsChangedEvent.StructuralImpact.NONE && changedElements.length == 1)
{
Object changedElement = changedElements[0];
if (changedElement instanceof CDOElement)
{
changedElement = ((CDOElement)changedElement).getParent();
}
if (structuralImpact == ElementsChangedEvent.StructuralImpact.PARENT)
{
changedElement = CDOExplorerUtil.getParent(changedElement);
}
viewerRefresh.addNotification(changedElement, true, true);
}
else
{
for (Object changedElement : changedElements)
{
viewerRefresh.addNotification(changedElement, false, true);
}
}
updatePropertySheetPage(changedElements);
}
}
private void updatePropertySheetPage(final Object element)
{
IWorkbenchPage workbenchPage = getWorkbenchPage();
PropertySheet propertySheet = getPropertySheet(workbenchPage);
if (propertySheet != null)
{
final IPage currentPage = propertySheet.getCurrentPage();
if (currentPage instanceof PropertySheetPage || currentPage instanceof TabbedPropertySheetPage)
{
final Control control = viewer.getControl();
if (!control.isDisposed())
{
control.getDisplay().asyncExec(new Runnable()
{
public void run()
{
if (!control.isDisposed())
{
IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
if (selection.size() == 1)
{
for (Object object : selection.toArray())
{
if (object == element)
{
if (currentPage instanceof PropertySheetPage)
{
((PropertySheetPage)currentPage).refresh();
}
else if (currentPage instanceof TabbedPropertySheetPage)
{
((TabbedPropertySheetPage)currentPage).refresh();
}
return;
}
}
}
}
}
});
}
}
}
}
private PropertySheet getPropertySheet(IWorkbenchPage workbenchPage)
{
for (IViewReference viewReference : workbenchPage.getViewReferences())
{
if ("org.eclipse.ui.views.PropertySheet".equals(viewReference.getId()))
{
IViewPart view = viewReference.getView(false);
if (view instanceof PropertySheet)
{
return (PropertySheet)view;
}
}
}
return null;
}
};
private final CDOCheckoutStateManager stateManager = new CDOCheckoutStateManager(this);
private final Map<Object, Object[]> childrenCache = new ConcurrentHashMap<Object, Object[]>();
private String viewerID;
private TreeViewer viewer;
private Object input;
public static final String PROJECT_EXPLORER_ID = "org.eclipse.ui.navigator.ProjectExplorer";
public CDOCheckoutContentProvider()
{
}
public void init(ICommonContentExtensionSite config)
{
viewerID = config.getService().getViewerId();
INSTANCES.put(viewerID, this);
CHECKOUT_MANAGER.addListener(checkoutManagerListener);
}
public void saveState(IMemento aMemento)
{
// Do nothing.
}
public void restoreState(IMemento aMemento)
{
// Do nothing.
}
public void dispose()
{
CHECKOUT_MANAGER.removeListener(checkoutManagerListener);
INSTANCES.remove(viewerID);
}
public void disposeWith(Control control)
{
control.addDisposeListener(new DisposeListener()
{
public void widgetDisposed(DisposeEvent e)
{
dispose();
}
});
}
public final CDOCheckoutStateManager getStateManager()
{
return stateManager;
}
public final TreeViewer getViewer()
{
return viewer;
}
public void inputChanged(Viewer newViewer, Object oldInput, Object newInput)
{
TreeViewer newTreeViewer = null;
if (newViewer instanceof TreeViewer)
{
newTreeViewer = (TreeViewer)newViewer;
}
if (newTreeViewer != viewer)
{
if (viewer != null)
{
viewer.removeOpenListener(this);
}
viewer = newTreeViewer;
if (viewer != null)
{
viewer.addOpenListener(this);
}
}
input = newInput;
stateManager.inputChanged(newTreeViewer, oldInput, newInput);
}
public Object getInput()
{
return input;
}
public Object[] getElements(Object object)
{
return getChildren(object);
}
public boolean hasChildren(Object object)
{
try
{
if (object instanceof IResource)
{
if (object instanceof IWorkspaceRoot)
{
return !CHECKOUT_MANAGER.isEmpty();
}
return false;
}
if (object instanceof ViewerUtil.Pending)
{
return false;
}
if (object instanceof CDOCheckout)
{
CDOCheckout checkout = (CDOCheckout)object;
switch (checkout.getState())
{
case Closing:
case Closed:
return false;
case Opening:
// This must be the ViewerUtil.Pending element.
return true;
case Open:
object = checkout.getRootObject();
break;
}
}
if (object instanceof CDOElement)
{
CDOElement checkoutElement = (CDOElement)object;
return checkoutElement.hasChildren();
}
if (GET_CHILDREN_FEATURES_METHOD != null && object instanceof EObject)
{
EObject eObject = (EObject)object;
InternalCDOObject cdoObject = getCDOObject(eObject);
if (cdoObject != null)
{
InternalCDORevision revision = cdoObject.cdoRevision(false);
if (revision != null)
{
ITreeItemContentProvider provider = (ITreeItemContentProvider)stateManager.adapt(object,
ITreeItemContentProvider.class);
if (provider instanceof ItemProviderAdapter)
{
try
{
return hasChildren(cdoObject, revision, (ItemProviderAdapter)provider);
}
catch (Exception ex)
{
//$FALL-THROUGH$
}
}
}
}
}
ITreeContentProvider contentProvider = stateManager.getContentProvider(object);
if (contentProvider != null)
{
return contentProvider.hasChildren(object);
}
}
catch (LifecycleException ex)
{
//$FALL-THROUGH$
}
catch (RuntimeException ex)
{
if (LifecycleUtil.isActive(object))
{
throw ex;
}
//$FALL-THROUGH$
}
return false;
}
public Object[] getChildren(Object object)
{
try
{
if (object instanceof IResource)
{
if (object instanceof IWorkspaceRoot)
{
return CHECKOUT_MANAGER.getCheckouts();
}
return ViewerUtil.NO_CHILDREN;
}
if (object instanceof ViewerUtil.Pending)
{
return ViewerUtil.NO_CHILDREN;
}
if (object instanceof CDOElement)
{
CDOElement checkoutElement = (CDOElement)object;
return checkoutElement.getChildren();
}
final Object originalObject = object;
Object[] children = childrenCache.remove(originalObject);
if (children != null)
{
return children;
}
CDOCheckout openingCheckout = null;
CDOCheckout checkout = null;
if (object instanceof CDOCheckout)
{
checkout = (CDOCheckout)object;
switch (checkout.getState())
{
case Closing:
case Closed:
return ViewerUtil.NO_CHILDREN;
case Opening:
openingCheckout = checkout;
break;
case Open:
object = checkout.getRootObject();
break;
}
}
final Object finalObject = object;
final CDOCheckout finalOpeningCheckout = openingCheckout;
final CDOCheckout finalCheckout = checkout;
final ITreeContentProvider contentProvider = stateManager.getContentProvider(finalObject);
if (contentProvider == null)
{
return ItemProvider.NO_ELEMENTS;
}
final List<CDORevision> loadedRevisions = new ArrayList<CDORevision>();
final List<CDOID> missingIDs = new ArrayList<CDOID>();
if (openingCheckout == null)
{
children = determineChildRevisions(object, loadedRevisions, missingIDs);
if (children != null)
{
return CDOCheckoutContentModifier.Registry.INSTANCE.modifyChildren(object, children);
}
}
synchronized (LOADING_OBJECTS)
{
LOADING_OBJECTS.add(originalObject);
}
new Job("Load " + finalObject)
{
@Override
protected IStatus run(IProgressMonitor monitor)
{
try
{
if (finalOpeningCheckout != null)
{
finalOpeningCheckout.open();
determineChildRevisions(finalObject, loadedRevisions, missingIDs);
}
if (!missingIDs.isEmpty())
{
CDOObject cdoObject = getCDOObject((EObject)finalObject);
CDOView view = cdoObject.cdoView();
CDORevisionManager revisionManager = view.getSession().getRevisionManager();
List<CDORevision> revisions = revisionManager.getRevisions(missingIDs, view, CDORevision.UNCHUNKED,
CDORevision.DEPTH_NONE, true);
loadedRevisions.addAll(revisions);
}
Object[] children;
CDOCheckout checkout = finalCheckout != null ? finalCheckout : CDOExplorerUtil.getCheckout(finalObject);
synchronized (checkout.getView())
{
children = contentProvider.getChildren(finalObject);
}
// Adjust possible legacy adapters.
for (int i = 0; i < children.length; i++)
{
Object child = children[i];
if (child instanceof InternalCDOObject)
{
InternalCDOObject cdoObject = (InternalCDOObject)child;
InternalEObject instance = cdoObject.cdoInternalInstance();
if (instance != cdoObject)
{
children[i] = instance;
}
}
}
children = CDOCheckoutContentModifier.Registry.INSTANCE.modifyChildren(finalObject, children);
childrenCache.put(originalObject, children);
}
catch (final Exception ex)
{
childrenCache.remove(originalObject);
if (finalOpeningCheckout != null)
{
finalOpeningCheckout.close();
}
OM.LOG.error(ex);
final Control control = viewer.getControl();
if (!control.isDisposed())
{
UIUtil.getDisplay().asyncExec(new Runnable()
{
public void run()
{
try
{
if (!control.isDisposed())
{
Shell shell = control.getShell();
String title = (finalOpeningCheckout != null ? "Open" : "Load") + " Error";
MessageDialog.openError(shell, title, ex.getMessage());
}
}
catch (Exception ex)
{
OM.LOG.error(ex);
}
}
});
}
}
CDOCheckoutViewerRefresh viewerRefresh = stateManager.getViewerRefresh();
viewerRefresh.addNotification(originalObject, true, true, new Runnable()
{
public void run()
{
synchronized (LOADING_OBJECTS)
{
LOADING_OBJECTS.remove(originalObject);
}
}
});
return Status.OK_STATUS;
}
}.schedule();
if (FIND_ITEM_METHOD != null)
{
try
{
Object widget = FIND_ITEM_METHOD.invoke(viewer, originalObject);
if (widget instanceof TreeItem)
{
TreeItem item = (TreeItem)widget;
TreeItem[] childItems = item.getItems();
int childCount = childItems.length;
if (childCount != 0)
{
List<Object> result = new ArrayList<Object>();
for (int i = 0; i < childCount; i++)
{
TreeItem childItem = childItems[i];
Object child = childItem.getData();
if (child != null)
{
result.add(child);
}
}
int size = result.size();
if (size != 0)
{
return result.toArray(new Object[size]);
}
}
}
}
catch (Exception ex)
{
//$FALL-THROUGH$
}
}
String text = "Loading...";
if (finalOpeningCheckout != null)
{
text = "Opening...";
}
return new Object[] { new ViewerUtil.Pending(originalObject, text) };
}
catch (LifecycleException ex)
{
//$FALL-THROUGH$
}
catch (RuntimeException ex)
{
if (LifecycleUtil.isActive(object))
{
throw ex;
}
//$FALL-THROUGH$
}
return ItemProvider.NO_ELEMENTS;
}
private Object[] determineChildRevisions(Object object, List<CDORevision> loadedRevisions, List<CDOID> missingIDs)
{
if (GET_CHILDREN_FEATURES_METHOD != null && object instanceof EObject)
{
EObject eObject = (EObject)object;
InternalCDOObject cdoObject = getCDOObject(eObject);
if (cdoObject != null)
{
InternalCDORevision revision = cdoObject.cdoRevision(false);
if (revision != null)
{
ITreeItemContentProvider provider = (ITreeItemContentProvider)stateManager.adapt(object,
ITreeItemContentProvider.class);
if (provider instanceof ItemProviderAdapter)
{
try
{
determineChildRevisions(cdoObject, revision, (ItemProviderAdapter)provider, loadedRevisions, missingIDs);
}
catch (Exception ex)
{
//$FALL-THROUGH$
}
if (missingIDs.isEmpty())
{
// All revisions are cached. Just return the objects without server round-trips.
ITreeContentProvider contentProvider = stateManager.getContentProvider(object);
if (contentProvider != null)
{
return contentProvider.getChildren(object);
}
}
}
}
}
}
return null;
}
public Object getParent(Object object)
{
try
{
if (object instanceof CDOCheckout)
{
return ResourcesPlugin.getWorkspace().getRoot();
}
if (object instanceof ViewerUtil.Pending)
{
return ((ViewerUtil.Pending)object).getParent();
}
if (object instanceof CDOElement)
{
CDOElement checkoutElement = (CDOElement)object;
return checkoutElement.getParent();
}
if (object instanceof EObject)
{
EObject eObject = CDOUtil.getEObject((EObject)object);
CDOElement element = CDOElement.getFor(eObject);
if (element != null)
{
return element;
}
ITreeContentProvider contentProvider = stateManager.getContentProvider(object);
if (contentProvider != null)
{
Object parent = contentProvider.getParent(object);
if (parent instanceof EObject)
{
EObject eParent = (EObject)parent;
Adapter adapter = EcoreUtil.getAdapter(eParent.eAdapters(), CDOCheckout.class);
if (adapter != null)
{
return adapter;
}
}
return parent;
}
}
}
catch (LifecycleException ex)
{
//$FALL-THROUGH$
}
catch (RuntimeException ex)
{
if (LifecycleUtil.isActive(object))
{
throw ex;
}
//$FALL-THROUGH$
}
return null;
}
public IPropertySource getPropertySource(Object object)
{
IPropertySourceProvider contentProvider = stateManager.getContentProvider(object);
if (contentProvider != null)
{
return contentProvider.getPropertySource(object);
}
return null;
}
public void selectObjects(final Object... objects)
{
final Control control = viewer.getControl();
if (!control.isDisposed())
{
final long end = System.currentTimeMillis() + 5000L;
final Display display = control.getDisplay();
display.asyncExec(new Runnable()
{
public void run()
{
if (control.isDisposed())
{
return;
}
for (Object object : objects)
{
LinkedList<Object> path = new LinkedList<Object>();
CDOCheckout checkout = CDOExplorerUtil.walkUp(object, path);
if (checkout != null)
{
viewer.setExpandedState(checkout, true);
if (!path.isEmpty())
{
path.removeFirst();
}
if (!path.isEmpty())
{
path.removeLast();
}
for (Object parent : path)
{
viewer.setExpandedState(parent, true);
}
}
}
viewer.setSelection(new StructuredSelection(objects), true);
IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
Set<Object> actual = new HashSet<Object>(Arrays.asList(selection.toArray()));
Set<Object> expected = new HashSet<Object>(Arrays.asList(objects));
if (!actual.equals(expected))
{
if (isObjectLoading(objects) || System.currentTimeMillis() < end)
{
display.timerExec(50, this);
}
}
}
});
}
}
public void open(OpenEvent event)
{
ISelection selection = event.getSelection();
if (selection instanceof IStructuredSelection)
{
IStructuredSelection ssel = (IStructuredSelection)selection;
if (ssel.size() == 1)
{
Object element = ssel.getFirstElement();
if (element instanceof CDOCheckout)
{
final CDOCheckout checkout = (CDOCheckout)element;
if (checkout.getState() == CDOCheckout.State.Closed)
{
// Simulate CheckoutOpenHandler.
new Job("Open " + checkout.getLabel())
{
@Override
protected IStatus run(IProgressMonitor monitor)
{
try
{
checkout.open();
}
catch (Exception ex)
{
OM.LOG.error(ex);
}
return Status.OK_STATUS;
}
}.schedule();
}
}
else if (element instanceof CDOResourceNode)
{
// Do nothing special.
}
else if (element instanceof EObject)
{
EObject eObject = (EObject)element;
Shell shell = getWorkbenchPage().getWorkbenchWindow().getShell();
ComposedAdapterFactory adapterFactory = stateManager.getAdapterFactory(eObject);
OpenWithActionProvider.editObject(shell, adapterFactory, eObject);
}
}
}
}
private IWorkbenchPage getWorkbenchPage()
{
if (viewer instanceof CommonViewer)
{
CommonViewer commonViewer = (CommonViewer)viewer;
return commonViewer.getCommonNavigator().getSite().getPage();
}
return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
}
private static InternalCDOObject getCDOObject(EObject eObject)
{
return (InternalCDOObject)CDOUtil.getCDOObject(eObject, false);
}
private static boolean hasChildren(InternalCDOObject cdoObject, InternalCDORevision revision,
ItemProviderAdapter provider) throws Exception
{
for (EStructuralFeature feature : getChildrenFeatures(cdoObject, provider))
{
if (feature.isMany())
{
if (!revision.isEmpty(feature))
{
return true;
}
}
else if (revision.getValue(feature) != null)
{
return true;
}
}
return false;
}
private static void determineChildRevisions(InternalCDOObject cdoObject, InternalCDORevision revision,
ItemProviderAdapter provider, List<CDORevision> loadedRevisions, List<CDOID> missingIDs) throws Exception
{
InternalCDOView view = cdoObject.cdoView();
InternalCDORevisionCache revisionCache = view.getSession().getRevisionManager().getCache();
for (EStructuralFeature feature : getChildrenFeatures(cdoObject, provider))
{
if (feature.isMany())
{
CDOList list = revision.getList(feature);
for (Object object : list)
{
determineChildRevision(loadedRevisions, missingIDs, view, revisionCache, object);
}
}
else
{
Object value = revision.getValue(feature);
determineChildRevision(loadedRevisions, missingIDs, view, revisionCache, value);
}
}
}
private static void determineChildRevision(List<CDORevision> loadedRevisions, List<CDOID> missingIDs,
InternalCDOView view, InternalCDORevisionCache cache, Object object)
{
if (object instanceof CDOID)
{
CDOID id = (CDOID)object;
CDORevision childRevision = cache.getRevision(id, view);
if (childRevision != null)
{
loadedRevisions.add(childRevision);
}
else
{
missingIDs.add(id);
}
}
}
@SuppressWarnings("unchecked")
private static Collection<? extends EStructuralFeature> getChildrenFeatures(InternalCDOObject cdoObject,
ItemProviderAdapter provider) throws Exception
{
return (Collection<? extends EStructuralFeature>)GET_CHILDREN_FEATURES_METHOD.invoke(provider, cdoObject);
}
private static Method getMethod(Class<?> c, String methodName, Class<?>... parameterTypes)
{
try
{
Method method = c.getDeclaredMethod(methodName, parameterTypes);
method.setAccessible(true);
return method;
}
catch (Throwable ex)
{
return null;
}
}
private static boolean isObjectLoading(Object... objects)
{
synchronized (LOADING_OBJECTS)
{
for (Object object : objects)
{
if (LOADING_OBJECTS.contains(object))
{
return true;
}
}
return false;
}
}
public static TreeViewer createTreeViewer(Composite container)
{
// TODO This is not lazy, async:
CDOItemProvider parentItemProvider = new CDOItemProvider(null)
{
@Override
public boolean hasChildren(Object element)
{
return getChildren(element).length != 0;
}
@Override
public Object[] getChildren(Object element)
{
List<Object> children = new ArrayList<Object>();
for (Object child : doGetChildren(element))
{
if (child instanceof CDOCheckout || child instanceof CDOResourceFolder)
{
children.add(child);
}
}
return children.toArray();
}
private Object[] doGetChildren(Object element)
{
if (element instanceof CDOCheckout)
{
CDOCheckout checkout = (CDOCheckout)element;
if (checkout.isOpen())
{
return checkout.getRootObject().eContents().toArray();
}
}
return super.getChildren(element);
}
@Override
public void fillContextMenu(IMenuManager manager, ITreeSelection selection)
{
// Do nothing.
}
};
CDOCheckoutContentProvider contentProvider = new CDOCheckoutContentProvider();
contentProvider.disposeWith(container);
CDOCheckoutLabelProvider labelProvider = new CDOCheckoutLabelProvider(contentProvider);
TreeViewer parentViewer = new TreeViewer(container, SWT.BORDER);
parentViewer.setContentProvider(parentItemProvider);
parentViewer.setLabelProvider(labelProvider);
parentViewer.setInput(CDOExplorerUtil.getCheckoutManager());
return parentViewer;
}
public static final CDOCheckoutContentProvider getInstance(String viewerID)
{
return INSTANCES.get(viewerID);
}
}