diff options
author | Eike Stepper | 2020-04-10 05:57:02 +0000 |
---|---|---|
committer | Eike Stepper | 2020-04-10 05:57:02 +0000 |
commit | fed3b44a5bc48864cb40184128feb66559c7648c (patch) | |
tree | 53ce813a3ef53f3b96eb5c7ead5144d82f863284 | |
parent | 92caf4e4d570e2a552d0508b19f0a52b1c4e9509 (diff) | |
download | cdo-fed3b44a5bc48864cb40184128feb66559c7648c.tar.gz cdo-fed3b44a5bc48864cb40184128feb66559c7648c.tar.xz cdo-fed3b44a5bc48864cb40184128feb66559c7648c.zip |
[561973] Make CDO Editor node expansion asynchronous and resilient to failures
https://bugs.eclipse.org/bugs/show_bug.cgi?id=561973
12 files changed, 891 insertions, 608 deletions
diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/bundle/OM.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/bundle/OM.java index 0a2d70a253..f7a446a19b 100644 --- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/bundle/OM.java +++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/bundle/OM.java @@ -52,7 +52,7 @@ public abstract class OM PREFS.init("PREF_REPOSITORY_TIMEOUT_DISABLED", false); //$NON-NLS-1$ public static final OMPreference<Boolean> PREF_REMEMBER_OPEN_EDITORS = // - PREFS.init("PREF_REMEMBER_OPEN_EDITORS", false); //$NON-NLS-1$ + PREFS.init("PREF_REMEMBER_OPEN_EDITORS", true); //$NON-NLS-1$ public static final OMPreference<Integer> PREF_DASHBOARD_HEIGHT = // PREFS.init("PREF_DASHBOARD_HEIGHT", 0); //$NON-NLS-1$ diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutContentProvider.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutContentProvider.java index 8503036f5a..c654b54b96 100644 --- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutContentProvider.java +++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutContentProvider.java @@ -11,11 +11,6 @@ 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; @@ -24,33 +19,19 @@ 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.internal.ui.CDOContentProvider; +import org.eclipse.emf.cdo.internal.ui.RunnableViewerRefresh; +import org.eclipse.emf.cdo.internal.ui.ViewerUtil; 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; @@ -60,7 +41,6 @@ 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; @@ -68,7 +48,6 @@ 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; @@ -78,7 +57,6 @@ 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; @@ -94,30 +72,23 @@ 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 +public class CDOCheckoutContentProvider extends CDOContentProvider<CDOCheckout> implements ICommonContentProvider, IPropertySourceProvider, IOpenListener { - private static final Map<String, CDOCheckoutContentProvider> INSTANCES = new HashMap<>(); - - private static final Set<Object> LOADING_OBJECTS = new HashSet<>(); - - private static final Method GET_CHILDREN_FEATURES_METHOD = getMethod(ItemProviderAdapter.class, "getChildrenFeatures", Object.class); + public static final String PROJECT_EXPLORER_ID = "org.eclipse.ui.navigator.ProjectExplorer"; - private static final Method FIND_ITEM_METHOD = getMethod(StructuredViewer.class, "findItem", Object.class); + private static final Map<String, CDOCheckoutContentProvider> INSTANCES = new HashMap<>(); private static final CDOCheckoutManager CHECKOUT_MANAGER = CDOExplorerUtil.getCheckoutManager(); @@ -126,7 +97,7 @@ public class CDOCheckoutContentProvider implements ICommonContentProvider, IProp @Override public void notifyEvent(IEvent event) { - CDOCheckoutViewerRefresh viewerRefresh = stateManager.getViewerRefresh(); + RunnableViewerRefresh viewerRefresh = stateManager.getViewerRefresh(); if (event instanceof IContainerEvent) { @@ -141,23 +112,23 @@ public class CDOCheckoutContentProvider implements ICommonContentProvider, IProp if (state == CDOCheckout.State.Opening) { // Trigger hasChildren(). - ViewerUtil.refresh(viewer, checkout); + ViewerUtil.refresh(getViewer(), checkout); // Trigger getChildren(). - ViewerUtil.expand(viewer, checkout, true); + ViewerUtil.expand(getViewer(), checkout, true); } else { if (state == CDOCheckout.State.Closed) { - ViewerUtil.expand(viewer, checkout, false); + ViewerUtil.expand(getViewer(), checkout, false); } viewerRefresh.addNotification(checkout, true, true); if (state == CDOCheckout.State.Open) { - ViewerUtil.expand(viewer, checkout, true); + ViewerUtil.expand(getViewer(), checkout, true); } updatePropertySheetPage(checkout); @@ -203,10 +174,11 @@ public class CDOCheckoutContentProvider implements ICommonContentProvider, IProp PropertySheet propertySheet = getPropertySheet(workbenchPage); if (propertySheet != null) { - final IPage currentPage = propertySheet.getCurrentPage(); + IPage currentPage = propertySheet.getCurrentPage(); if (currentPage instanceof PropertySheetPage || currentPage instanceof TabbedPropertySheetPage) { - final Control control = viewer.getControl(); + TreeViewer viewer = getViewer(); + Control control = viewer.getControl(); if (!control.isDisposed()) { control.getDisplay().asyncExec(new Runnable() @@ -269,16 +241,8 @@ public class CDOCheckoutContentProvider implements ICommonContentProvider, IProp private final CDOCheckoutStateManager stateManager = new CDOCheckoutStateManager(this); - private final Map<Object, Object[]> childrenCache = new ConcurrentHashMap<>(); - private String viewerID; - private TreeViewer viewer; - - private Object input; - - public static final String PROJECT_EXPLORER_ID = "org.eclipse.ui.navigator.ProjectExplorer"; - public CDOCheckoutContentProvider() { } @@ -327,497 +291,54 @@ public class CDOCheckoutContentProvider implements ICommonContentProvider, IProp return stateManager; } - public final TreeViewer getViewer() - { - return viewer; - } - @Override 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; - } - - @Override - public Object[] getElements(Object object) - { - return getChildren(object); + super.inputChanged(newViewer, oldInput, newInput); + stateManager.inputChanged(getViewer(), oldInput, newInput); } @Override 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) - { - try - { - ITreeItemContentProvider provider = (ITreeItemContentProvider)stateManager.adapt(object, ITreeItemContentProvider.class); - if (provider instanceof ItemProviderAdapter) - { - 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) + if (object instanceof IResource) { - //$FALL-THROUGH$ - } - catch (RuntimeException ex) - { - if (LifecycleUtil.isActive(object)) + if (object instanceof IWorkspaceRoot) { - throw ex; + return !CHECKOUT_MANAGER.isEmpty(); } - //$FALL-THROUGH$ + return false; } - return false; + return super.hasChildren(object); } @Override public Object[] getChildren(Object object) { - try + if (object instanceof IResource) { - if (object instanceof IResource) - { - if (object instanceof IWorkspaceRoot) - { - return CHECKOUT_MANAGER.getCheckouts(); - } - - return ViewerUtil.NO_CHILDREN; - } - - if (object instanceof ViewerUtil.Pending) + if (object instanceof IWorkspaceRoot) { - return ViewerUtil.NO_CHILDREN; + return CHECKOUT_MANAGER.getCheckouts(); } - 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 ITreeContentProvider contentProvider = stateManager.getContentProvider(finalObject); - if (contentProvider == null) - { - return ItemProvider.NO_ELEMENTS; - } - - final List<CDORevision> loadedRevisions = new ArrayList<>(); - final List<CDOID> missingIDs = new ArrayList<>(); - - if (openingCheckout == null) - { - children = determineChildRevisions(object, loadedRevisions, missingIDs); - if (children != null) - { - return CDOCheckoutContentModifier.Registry.INSTANCE.modifyChildren(object, children); - } - } - - boolean firstLoad; - synchronized (LOADING_OBJECTS) - { - firstLoad = LOADING_OBJECTS.add(originalObject); - } - - if (firstLoad || finalOpeningCheckout == null) - { - Job job = 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 = 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() - { - @Override - 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() - { - @Override - public void run() - { - synchronized (LOADING_OBJECTS) - { - LOADING_OBJECTS.remove(originalObject); - } - } - }); - - return Status.OK_STATUS; - } - }; - - job.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<>(); - 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) }; + return ViewerUtil.NO_CHILDREN; } - 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) - { - try - { - ITreeItemContentProvider provider = (ITreeItemContentProvider)stateManager.adapt(object, ITreeItemContentProvider.class); - if (provider instanceof ItemProviderAdapter) - { - determineChildRevisions(cdoObject, revision, (ItemProviderAdapter)provider, loadedRevisions, missingIDs); - - 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); - } - } - } - } - catch (Exception ex) - { - //$FALL-THROUGH$ - } - } - } - } - - return null; + return super.getChildren(object); } @Override 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) + if (object instanceof CDOCheckout) { - //$FALL-THROUGH$ - } - catch (RuntimeException ex) - { - if (LifecycleUtil.isActive(object)) - { - throw ex; - } - - //$FALL-THROUGH$ + return ResourcesPlugin.getWorkspace().getRoot(); } - return null; + return super.getParent(object); } @Override @@ -834,7 +355,8 @@ public class CDOCheckoutContentProvider implements ICommonContentProvider, IProp public void selectObjects(final Object... objects) { - final Control control = viewer.getControl(); + TreeViewer viewer = getViewer(); + Control control = viewer.getControl(); if (!control.isDisposed()) { final long end = System.currentTimeMillis() + 5000L; @@ -943,121 +465,96 @@ public class CDOCheckoutContentProvider implements ICommonContentProvider, IProp } } - private IWorkbenchPage getWorkbenchPage() + @Override + protected void hookViewer(TreeViewer viewer) { - if (viewer instanceof CommonViewer) - { - CommonViewer commonViewer = (CommonViewer)viewer; - return commonViewer.getCommonNavigator().getSite().getPage(); - } + viewer.addOpenListener(this); + } - return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + @Override + protected void unhookViewer(TreeViewer viewer) + { + viewer.removeOpenListener(this); } - private static InternalCDOObject getCDOObject(EObject eObject) + @Override + protected Object adapt(Object target, Object type) { - return (InternalCDOObject)CDOUtil.getCDOObject(eObject, false); + return stateManager.adapt(target, type); } - private static boolean hasChildren(InternalCDOObject cdoObject, InternalCDORevision revision, ItemProviderAdapter provider) throws Exception + @Override + protected Object[] modifyChildren(Object parent, Object[] children) { - for (EStructuralFeature feature : getChildrenFeatures(cdoObject, provider)) - { - if (feature.isMany()) - { - if (!revision.isEmpty(feature)) - { - return true; - } - } - else if (revision.getValue(feature) != null) - { - return true; - } - } + return CDOCheckoutContentModifier.Registry.INSTANCE.modifyChildren(parent, children); + } - return false; + @Override + protected ITreeContentProvider getContentProvider(Object object) + { + return stateManager.getContentProvider(object); } - private static void determineChildRevisions(InternalCDOObject cdoObject, InternalCDORevision revision, ItemProviderAdapter provider, - List<CDORevision> loadedRevisions, List<CDOID> missingIDs) throws Exception + @Override + protected RunnableViewerRefresh getViewerRefresh() { - InternalCDOView view = cdoObject.cdoView(); - InternalCDORevisionCache revisionCache = view.getSession().getRevisionManager().getCache(); + return stateManager.getViewerRefresh(); + } - for (EStructuralFeature feature : getChildrenFeatures(cdoObject, provider)) - { - if (feature.isMany()) - { - CDOList list = revision.getListOrNull(feature); - if (list != null) - { - for (Object object : list) - { - determineChildRevision(loadedRevisions, missingIDs, view, revisionCache, object); - } - } - } - else - { - Object value = revision.getValue(feature); - determineChildRevision(loadedRevisions, missingIDs, view, revisionCache, value); - } - } + @Override + protected boolean isContext(Object object) + { + return object instanceof CDOCheckout; } - private static void determineChildRevision(List<CDORevision> loadedRevisions, List<CDOID> missingIDs, InternalCDOView view, InternalCDORevisionCache cache, - Object object) + @Override + protected ContextState getContextState(CDOCheckout checkout) { - if (object instanceof CDOID) + switch (checkout.getState()) { - CDOID id = (CDOID)object; - CDORevision childRevision = cache.getRevision(id, view); - if (childRevision != null) - { - loadedRevisions.add(childRevision); - } - else - { - missingIDs.add(id); - } + case Closing: + case Closed: + return ContextState.Closed; + + case Opening: + return ContextState.Opening; + + case Open: + return ContextState.Open; + + default: + throw new IllegalStateException("Unexpected checkout state: " + checkout); } } - @SuppressWarnings("unchecked") - private static Collection<? extends EStructuralFeature> getChildrenFeatures(InternalCDOObject cdoObject, ItemProviderAdapter provider) throws Exception + @Override + protected void openContext(CDOCheckout checkout) { - return (Collection<? extends EStructuralFeature>)GET_CHILDREN_FEATURES_METHOD.invoke(provider, cdoObject); + checkout.open(); } - private static Method getMethod(Class<?> c, String methodName, Class<?>... parameterTypes) + @Override + protected void closeContext(CDOCheckout checkout) { - try - { - Method method = c.getDeclaredMethod(methodName, parameterTypes); - method.setAccessible(true); - return method; - } - catch (Throwable ex) - { - return null; - } + checkout.close(); } - private static boolean isObjectLoading(Object... objects) + @Override + protected Object getRootObject(CDOCheckout checkout) { - synchronized (LOADING_OBJECTS) - { - for (Object object : objects) - { - if (LOADING_OBJECTS.contains(object)) - { - return true; - } - } + return checkout.getRootObject(); + } - return false; + private IWorkbenchPage getWorkbenchPage() + { + TreeViewer viewer = getViewer(); + if (viewer instanceof CommonViewer) + { + CommonViewer commonViewer = (CommonViewer)viewer; + return commonViewer.getCommonNavigator().getSite().getPage(); } + + return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); } public static TreeViewer createTreeViewer(Composite container) diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutEditorInput.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutEditorInput.java index 1ed275bc07..c1574b4db7 100644 --- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutEditorInput.java +++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutEditorInput.java @@ -24,6 +24,7 @@ import org.eclipse.emf.cdo.util.CDOURIUtil; import org.eclipse.emf.cdo.util.CDOUtil; import org.eclipse.emf.cdo.view.CDOView; +import org.eclipse.net4j.util.CheckUtil; import org.eclipse.net4j.util.om.monitor.EclipseMonitor; import org.eclipse.net4j.util.om.monitor.OMMonitor; import org.eclipse.net4j.util.om.monitor.OMMonitor.Async; @@ -58,6 +59,7 @@ public class CDOCheckoutEditorInput extends PlatformObject implements CDOEditorI public CDOCheckoutEditorInput(URI uri) { + CheckUtil.checkArg(uri, "uri is null"); this.uri = uri; } diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutLabelProvider.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutLabelProvider.java index 113545c88c..ea479db7b2 100644 --- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutLabelProvider.java +++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutLabelProvider.java @@ -11,7 +11,7 @@ package org.eclipse.emf.cdo.explorer.ui.checkouts; import org.eclipse.emf.cdo.explorer.CDOExplorerElement; -import org.eclipse.emf.cdo.explorer.ui.ViewerUtil; +import org.eclipse.emf.cdo.internal.ui.ViewerUtil; import org.eclipse.emf.cdo.transfer.CDOTransferElement; import org.eclipse.net4j.util.StringUtil; diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutState.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutState.java index f4943d57f3..05f54b52c0 100644 --- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutState.java +++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutState.java @@ -16,8 +16,8 @@ import org.eclipse.emf.cdo.eresource.CDOResourceNode; 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.ui.ViewerUtil; import org.eclipse.emf.cdo.explorer.ui.bundle.OM; +import org.eclipse.emf.cdo.internal.ui.ViewerUtil; import org.eclipse.emf.cdo.internal.ui.editor.CDOEditor; import org.eclipse.emf.cdo.ui.CDOEditorUtil; import org.eclipse.emf.cdo.ui.CDOLabelDecorator; diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutStateManager.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutStateManager.java index 1ad21940fa..23a1cb650a 100644 --- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutStateManager.java +++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutStateManager.java @@ -14,6 +14,7 @@ import org.eclipse.emf.cdo.explorer.CDOExplorerUtil; import org.eclipse.emf.cdo.explorer.checkouts.CDOCheckout; import org.eclipse.emf.cdo.explorer.ui.checkouts.CDOCheckoutState.ContentProvider; import org.eclipse.emf.cdo.explorer.ui.checkouts.CDOCheckoutState.LabelProvider; +import org.eclipse.emf.cdo.internal.ui.RunnableViewerRefresh; import org.eclipse.net4j.util.lifecycle.LifecycleException; @@ -38,7 +39,7 @@ public final class CDOCheckoutStateManager private final CDOCheckoutContentProvider mainContentProvider; - private CDOCheckoutViewerRefresh viewerRefresh; + private RunnableViewerRefresh viewerRefresh; public CDOCheckoutStateManager(CDOCheckoutContentProvider mainContentProvider) { @@ -55,7 +56,7 @@ public final class CDOCheckoutStateManager return resourceManager; } - public CDOCheckoutViewerRefresh getViewerRefresh() + public RunnableViewerRefresh getViewerRefresh() { return viewerRefresh; } @@ -98,7 +99,7 @@ public final class CDOCheckoutStateManager public void inputChanged(TreeViewer newTreeViewer, Object oldInput, Object newInput) { - viewerRefresh = new CDOCheckoutViewerRefresh(newTreeViewer); + viewerRefresh = new RunnableViewerRefresh(newTreeViewer); for (CDOCheckoutState state : getStates()) { diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/CDORepositoryItemProvider.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/CDORepositoryItemProvider.java index ea95b72f15..17aecfa5cb 100644 --- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/CDORepositoryItemProvider.java +++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/CDORepositoryItemProvider.java @@ -19,8 +19,8 @@ import org.eclipse.emf.cdo.explorer.repositories.CDORepository.IDGeneration; import org.eclipse.emf.cdo.explorer.repositories.CDORepository.VersioningMode; import org.eclipse.emf.cdo.explorer.repositories.CDORepositoryManager; import org.eclipse.emf.cdo.explorer.repositories.CDORepositoryManager.RepositoryConnectionEvent; -import org.eclipse.emf.cdo.explorer.ui.ViewerUtil; import org.eclipse.emf.cdo.explorer.ui.bundle.OM; +import org.eclipse.emf.cdo.internal.ui.ViewerUtil; import org.eclipse.emf.cdo.ui.shared.SharedIcons; import org.eclipse.net4j.util.container.IContainer; diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/wizards/MasterRepositoryController.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/wizards/MasterRepositoryController.java index b771327e82..d9059cb155 100644 --- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/wizards/MasterRepositoryController.java +++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/wizards/MasterRepositoryController.java @@ -16,8 +16,8 @@ import org.eclipse.emf.cdo.admin.CDOAdminClientRepository; import org.eclipse.emf.cdo.admin.CDOAdminClientUtil; import org.eclipse.emf.cdo.explorer.repositories.CDORepository.IDGeneration; import org.eclipse.emf.cdo.explorer.repositories.CDORepository.VersioningMode; -import org.eclipse.emf.cdo.explorer.ui.ViewerUtil; import org.eclipse.emf.cdo.explorer.ui.bundle.OM; +import org.eclipse.emf.cdo.internal.ui.ViewerUtil; import org.eclipse.emf.cdo.net4j.CDONet4jSession; import org.eclipse.emf.cdo.net4j.CDONet4jSessionConfiguration; import org.eclipse.emf.cdo.net4j.CDONet4jUtil; diff --git a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/CDOContentProvider.java b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/CDOContentProvider.java new file mode 100644 index 0000000000..13311c66ac --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/CDOContentProvider.java @@ -0,0 +1,670 @@ +/* + * Copyright (c) 2015, 2016, 2018, 2019 Eike Stepper (Loehne, 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.internal.ui; + +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.internal.ui.bundle.OM; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionCache; +import org.eclipse.emf.cdo.util.CDOUtil; +import org.eclipse.emf.cdo.view.CDOView; + +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.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +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.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.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.StructuredViewer; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TreeItem; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author Eike Stepper + */ +public abstract class CDOContentProvider<CONTEXT> implements ITreeContentProvider +{ + private static final Set<Object> LOADING_OBJECTS = new HashSet<>(); + + 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 final Map<Object, Object[]> childrenCache = new ConcurrentHashMap<>(); + + private TreeViewer viewer; + + private Object input; + + public CDOContentProvider() + { + } + + public final TreeViewer getViewer() + { + return viewer; + } + + @Override + 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) + { + unhookViewer(viewer); + } + + viewer = newTreeViewer; + + if (viewer != null) + { + hookViewer(viewer); + } + } + + input = newInput; + } + + public Object getInput() + { + return input; + } + + @Override + public Object[] getElements(Object object) + { + return getChildren(object); + } + + @Override + public boolean hasChildren(Object object) + { + try + { + if (object instanceof ViewerUtil.Pending) + { + return false; + } + + if (isContext(object)) + { + @SuppressWarnings("unchecked") + CONTEXT context = (CONTEXT)object; + + switch (getContextState(context)) + { + case Closed: + return false; + + case Opening: + // This must be the ViewerUtil.Pending element. + return true; + + case Open: + object = getRootObject(context); + 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) + { + try + { + ITreeItemContentProvider provider = (ITreeItemContentProvider)adapt(object, ITreeItemContentProvider.class); + if (provider instanceof ItemProviderAdapter) + { + return hasChildren(cdoObject, revision, (ItemProviderAdapter)provider); + } + } + catch (Exception ex) + { + //$FALL-THROUGH$ + } + } + } + } + + ITreeContentProvider contentProvider = 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; + } + + @Override + public Object[] getChildren(Object object) + { + try + { + 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; + } + + CONTEXT openingCheckout = null; + if (isContext(object)) + { + @SuppressWarnings("unchecked") + CONTEXT context = (CONTEXT)object; + + switch (getContextState(context)) + { + case Closed: + return ViewerUtil.NO_CHILDREN; + + case Opening: + openingCheckout = context; + break; + + case Open: + object = getRootObject(context); + break; + } + } + + final Object finalObject = object; + final CONTEXT finalOpeningContext = openingCheckout; + + final ITreeContentProvider contentProvider = getContentProvider(finalObject); + if (contentProvider == null) + { + return ItemProvider.NO_ELEMENTS; + } + + final List<CDORevision> loadedRevisions = new ArrayList<>(); + final List<CDOID> missingIDs = new ArrayList<>(); + + if (finalOpeningContext == null) + { + children = determineChildRevisions(object, loadedRevisions, missingIDs); + if (children != null) + { + return modifyChildren(object, children); + } + } + + boolean firstLoad; + synchronized (LOADING_OBJECTS) + { + firstLoad = LOADING_OBJECTS.add(originalObject); + } + + if (firstLoad || finalOpeningContext == null) + { + Job job = new Job("Load " + finalObject) + { + @Override + protected IStatus run(IProgressMonitor monitor) + { + try + { + if (finalOpeningContext != null) + { + openContext(finalOpeningContext); + 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 = 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 = modifyChildren(finalObject, children); + childrenCache.put(originalObject, children); + } + catch (final Exception ex) + { + childrenCache.remove(originalObject); + + if (finalOpeningContext != null) + { + closeContext(finalOpeningContext); + } + + OM.LOG.error(ex); + + final Control control = viewer.getControl(); + if (!control.isDisposed()) + { + UIUtil.getDisplay().asyncExec(new Runnable() + { + @Override + public void run() + { + try + { + if (!control.isDisposed()) + { + Shell shell = control.getShell(); + String title = (finalOpeningContext != null ? "Open" : "Load") + " Error"; + MessageDialog.openError(shell, title, ex.getMessage()); + } + } + catch (Exception ex) + { + OM.LOG.error(ex); + } + } + }); + } + } + + RunnableViewerRefresh viewerRefresh = getViewerRefresh(); + viewerRefresh.addNotification(originalObject, true, true, () -> { + synchronized (LOADING_OBJECTS) + { + LOADING_OBJECTS.remove(originalObject); + } + }); + + return Status.OK_STATUS; + } + }; + + job.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<>(); + 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 (finalOpeningContext != 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; + } + + @Override + public Object getParent(Object object) + { + try + { + 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 = getContentProvider(object); + if (contentProvider != null) + { + return contentProvider.getParent(object); + } + } + } + catch (LifecycleException ex) + { + //$FALL-THROUGH$ + } + catch (RuntimeException ex) + { + if (LifecycleUtil.isActive(object)) + { + throw ex; + } + + //$FALL-THROUGH$ + } + + return null; + } + + protected void hookViewer(TreeViewer viewer) + { + } + + protected void unhookViewer(TreeViewer viewer) + { + } + + protected abstract Object adapt(Object target, Object type); + + protected abstract Object[] modifyChildren(Object parent, Object[] children); + + protected abstract ITreeContentProvider getContentProvider(Object object); + + protected abstract RunnableViewerRefresh getViewerRefresh(); + + protected abstract boolean isContext(Object object); + + protected abstract ContextState getContextState(CONTEXT context); + + protected abstract void openContext(CONTEXT context); + + protected abstract void closeContext(CONTEXT context); + + protected abstract Object getRootObject(CONTEXT context); + + 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) + { + try + { + ITreeItemContentProvider provider = (ITreeItemContentProvider)adapt(object, ITreeItemContentProvider.class); + if (provider instanceof ItemProviderAdapter) + { + determineChildRevisions(cdoObject, revision, (ItemProviderAdapter)provider, loadedRevisions, missingIDs); + + if (missingIDs.isEmpty()) + { + // All revisions are cached. Just return the objects without server round-trips. + ITreeContentProvider contentProvider = getContentProvider(object); + if (contentProvider != null) + { + return contentProvider.getChildren(object); + } + } + } + } + catch (Exception ex) + { + //$FALL-THROUGH$ + } + } + } + } + + return null; + } + + protected static boolean isObjectLoading(Object... objects) + { + synchronized (LOADING_OBJECTS) + { + for (Object object : objects) + { + if (LOADING_OBJECTS.contains(object)) + { + return true; + } + } + + return false; + } + } + + 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.getListOrNull(feature); + if (list != null) + { + 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; + } + } + + /** + * @author Eike Stepper + */ + public static enum ContextState + { + Opening, Open, Closed + } +} diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutViewerRefresh.java b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/RunnableViewerRefresh.java index 8b86b431f7..480598a18e 100644 --- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutViewerRefresh.java +++ b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/RunnableViewerRefresh.java @@ -8,7 +8,7 @@ * Contributors: * Eike Stepper - initial API and implementation */ -package org.eclipse.emf.cdo.explorer.ui.checkouts; +package org.eclipse.emf.cdo.internal.ui; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.edit.provider.IViewerNotification; @@ -23,11 +23,11 @@ import java.util.List; /** * @author Eike Stepper */ -public final class CDOCheckoutViewerRefresh extends ViewerRefresh +public final class RunnableViewerRefresh extends ViewerRefresh { private final Viewer viewer; - public CDOCheckoutViewerRefresh(Viewer viewer) + public RunnableViewerRefresh(Viewer viewer) { super(viewer); this.viewer = viewer; diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/ViewerUtil.java b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/ViewerUtil.java index 3ed3d5492e..fa9831036b 100644 --- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/ViewerUtil.java +++ b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/ViewerUtil.java @@ -8,7 +8,7 @@ * Contributors: * Eike Stepper - initial API and implementation */ -package org.eclipse.emf.cdo.explorer.ui; +package org.eclipse.emf.cdo.internal.ui; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.StructuredViewer; @@ -195,5 +195,11 @@ public final class ViewerUtil { return text; } + + @Override + public String toString() + { + return text; + } } } diff --git a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/editor/CDOEditor.java b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/editor/CDOEditor.java index 82364be6a6..2317f4e9cb 100644 --- a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/editor/CDOEditor.java +++ b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/editor/CDOEditor.java @@ -21,6 +21,9 @@ import org.eclipse.emf.cdo.common.model.CDOPackageRegistry; import org.eclipse.emf.cdo.common.model.CDOPackageUnit; import org.eclipse.emf.cdo.common.model.EMFUtil; import org.eclipse.emf.cdo.eresource.CDOResource; +import org.eclipse.emf.cdo.internal.ui.CDOContentProvider; +import org.eclipse.emf.cdo.internal.ui.RunnableViewerRefresh; +import org.eclipse.emf.cdo.internal.ui.ViewerUtil; import org.eclipse.emf.cdo.internal.ui.actions.TransactionalBackgroundAction; import org.eclipse.emf.cdo.internal.ui.bundle.OM; import org.eclipse.emf.cdo.internal.ui.dialogs.BulkAddDialog; @@ -50,6 +53,7 @@ import org.eclipse.net4j.util.StringUtil; import org.eclipse.net4j.util.om.trace.ContextTracer; import org.eclipse.net4j.util.ui.actions.LongRunningAction; import org.eclipse.net4j.util.ui.actions.SafeAction; +import org.eclipse.net4j.util.ui.views.ContainerItemProvider; import org.eclipse.emf.common.command.BasicCommandStack; import org.eclipse.emf.common.command.Command; @@ -125,6 +129,7 @@ import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.StructuredViewer; @@ -1508,8 +1513,33 @@ public class CDOEditor extends MultiPageEditorPart implements IEditingDomainProv */ protected IContentProvider createContentProvider() { - return new AdapterFactoryContentProvider(adapterFactory) + class DelegateContentProvider extends AdapterFactoryContentProvider { + public DelegateContentProvider(AdapterFactory adapterFactory) + { + super(adapterFactory); + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) + { + super.inputChanged(viewer, oldInput, newInput); + + if (viewer != null) + { + viewerRefresh = new RunnableViewerRefresh(viewer); + } + else + { + viewerRefresh = null; + } + } + + public RunnableViewerRefresh getViewerRefresh() + { + return (RunnableViewerRefresh)viewerRefresh; + } + @Override public boolean hasChildren(Object object) { @@ -1527,6 +1557,72 @@ public class CDOEditor extends MultiPageEditorPart implements IEditingDomainProv return false; } } + } + + DelegateContentProvider delegate = new DelegateContentProvider(adapterFactory); + + return new CDOContentProvider<CDOView>() + { + @Override + public void inputChanged(Viewer newViewer, Object oldInput, Object newInput) + { + super.inputChanged(newViewer, oldInput, newInput); + delegate.inputChanged(newViewer, oldInput, newInput); + } + + @Override + protected Object adapt(Object target, Object type) + { + return adapterFactory.adapt(target, type); + } + + @Override + protected Object[] modifyChildren(Object parent, Object[] children) + { + return children; + } + + @Override + protected ITreeContentProvider getContentProvider(Object object) + { + return delegate; + } + + @Override + protected RunnableViewerRefresh getViewerRefresh() + { + return delegate.getViewerRefresh(); + } + + @Override + protected boolean isContext(Object object) + { + return false; + } + + @Override + protected ContextState getContextState(CDOView view) + { + throw new UnsupportedOperationException(); + } + + @Override + protected void openContext(CDOView view) + { + throw new UnsupportedOperationException(); + } + + @Override + protected void closeContext(CDOView view) + { + throw new UnsupportedOperationException(); + } + + @Override + protected Object getRootObject(CDOView view) + { + throw new UnsupportedOperationException(); + } }; } @@ -1542,6 +1638,11 @@ public class CDOEditor extends MultiPageEditorPart implements IEditingDomainProv { try { + if (element instanceof ViewerUtil.Pending) + { + return ContainerItemProvider.PENDING_IMAGE; + } + Image image = super.getImage(element); if (image != null) { @@ -1564,6 +1665,12 @@ public class CDOEditor extends MultiPageEditorPart implements IEditingDomainProv { try { + if (element instanceof ViewerUtil.Pending) + { + ViewerUtil.Pending pending = (ViewerUtil.Pending)element; + return pending.getText(); + } + String text = super.getText(element); if (!StringUtil.isEmpty(text)) { |