diff options
4 files changed, 365 insertions, 15 deletions
diff --git a/bundles/org.eclipse.wst.xsd.ui/src-adt-xsd/org/eclipse/wst/xsd/ui/internal/text/XSDModelDelayedReconciler.java b/bundles/org.eclipse.wst.xsd.ui/src-adt-xsd/org/eclipse/wst/xsd/ui/internal/text/XSDModelDelayedReconciler.java new file mode 100644 index 0000000000..02b7b6d76b --- /dev/null +++ b/bundles/org.eclipse.wst.xsd.ui/src-adt-xsd/org/eclipse/wst/xsd/ui/internal/text/XSDModelDelayedReconciler.java @@ -0,0 +1,195 @@ +/******************************************************************************* + * Copyright (c) 2009 IBM Corporation 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: + * IBM Corporation - Initial API and implementation + *******************************************************************************/ +package org.eclipse.wst.xsd.ui.internal.text; + + +import java.util.ArrayList; +import java.util.List; + +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.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.progress.UIJob; +import org.eclipse.wst.xsd.ui.internal.editor.InternalXSDMultiPageEditor; +import org.eclipse.xsd.XSDConcreteComponent; +import org.eclipse.xsd.XSDSchema; +import org.w3c.dom.Element; + + +/** + * Provides delayed reconciliation between the SSE DOM and the XSD EMF model. + * Changes in the DOM are queued and processed by a UI job. When a new request + * comes in, the current run is cancelled, the new request is added to the queue, + * then the job is re-scheduled. + */ +public class XSDModelDelayedReconciler +{ + /** + * The model reconciler job. + */ + private ReconcilerJob reconcilerJob; + + /** + * The time in milliseconds to delay updating the EMF model. + */ + private static final int DELAY = 300; + + /** + * The elements to reconcile. + */ + private List elementsToReconcile = new ArrayList(); + + /** + * Determines if the delayed reconciler should kick in. + */ + public boolean shouldDelay(XSDSchema schema) + { + boolean shouldDelay = false; + + // The delayed reconciler should not be used when the editor is in graphical editing mode. + + IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + IWorkbenchPage workbenchPage = workbenchWindow.getActivePage(); + IEditorPart editorPart = workbenchPage != null ? workbenchPage.getActiveEditor() : null; + if (editorPart != null && editorPart instanceof InternalXSDMultiPageEditor) + { + InternalXSDMultiPageEditor xsdEditor = (InternalXSDMultiPageEditor)editorPart; + shouldDelay = xsdEditor.isSourcePageActive(); + } + + return shouldDelay; + } + + /** + * Updates the XSD EMF component corresponding to the DOM element. + * + * @param element the changed element. + * @param schema the containing schema. + */ + public void elementChanged(Element element, XSDSchema schema) + { + synchronized (elementsToReconcile) + { + // The number of elements should be small so a linear search should be fine. + + if (!elementsToReconcile.contains(element)) + { + elementsToReconcile.add(element); + } + + if (reconcilerJob == null) + { + reconcilerJob = new ReconcilerJob(schema); + } + + reconcilerJob.schedule(DELAY); + } + } + + /** + * A UI job used to reconcile the XSD EMF model with the associated SSE DOM. + */ + class ReconcilerJob extends UIJob + { + /** + * The target schema. + */ + private XSDSchema schema; + + /** + * The number of times allowed to wake up and do nothing. + */ + private static final int MAX_INACTIVE_COUNT = 10; + + /** + * The job will terminate once this counter reaches MAX_INACTIVE_COUNT. + */ + private int timesAwakeAndIdle = 0; + + /** + * Constructs the reconciler job and configures some of its properties. + */ + public ReconcilerJob(XSDSchema schema) + { + super("Reconciling the XSD EMF model"); //$NON-NLS-1$ + setSystem(true); + setPriority(Job.LONG); + this.schema = schema; + } + + public IStatus runInUIThread(IProgressMonitor monitor) + { + if (monitor.isCanceled()) + { + return Status.CANCEL_STATUS; + } + + Element[] elements = null; + + synchronized (elementsToReconcile) + { + if (!elementsToReconcile.isEmpty()) + { + elements = new Element[elementsToReconcile.size()]; + elementsToReconcile.toArray(elements); + elementsToReconcile.clear(); + } + else + { + if (shouldTerminate()) + { + reconcilerJob = null; + return Status.CANCEL_STATUS; + } + } + } + + reconcile(elements); + + schedule(DELAY); + + return Status.OK_STATUS; + } + + private void reconcile(Element[] modifiedElements) + { + if (modifiedElements != null) + { + for (int index = 0; index < modifiedElements.length; index++) + { + Element modifiedElement = modifiedElements[index]; + + reconcile(modifiedElement); + } + } + } + + private void reconcile(Element modifiedElement) + { + if (modifiedElement != null) + { + XSDConcreteComponent concreteComponent = schema.getCorrespondingComponent(modifiedElement); + concreteComponent.elementChanged(modifiedElement); + } + } + + private boolean shouldTerminate() + { + return timesAwakeAndIdle++ == MAX_INACTIVE_COUNT; + } + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xsd.ui/src-adt-xsd/org/eclipse/wst/xsd/ui/internal/text/XSDModelReconcileAdapter.java b/bundles/org.eclipse.wst.xsd.ui/src-adt-xsd/org/eclipse/wst/xsd/ui/internal/text/XSDModelReconcileAdapter.java index 80a6db576b..44b0626f8b 100644 --- a/bundles/org.eclipse.wst.xsd.ui/src-adt-xsd/org/eclipse/wst/xsd/ui/internal/text/XSDModelReconcileAdapter.java +++ b/bundles/org.eclipse.wst.xsd.ui/src-adt-xsd/org/eclipse/wst/xsd/ui/internal/text/XSDModelReconcileAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2008 IBM Corporation and others. + * Copyright (c) 2004, 2009 IBM Corporation 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 @@ -24,11 +24,13 @@ import org.w3c.dom.Node; public class XSDModelReconcileAdapter extends ModelReconcileAdapter { protected XSDSchema schema; + protected XSDModelDelayedReconciler delayedReconciler; public XSDModelReconcileAdapter(Document document, XSDSchema schema) { super(document); this.schema = schema; + this.delayedReconciler = new XSDModelDelayedReconciler(); } protected void handleNodeChanged(Node node) @@ -50,9 +52,17 @@ public class XSDModelReconcileAdapter extends ModelReconcileAdapter if (node instanceof Element) { - XSDConcreteComponent concreteComponent = schema.getCorrespondingComponent(node); - concreteComponent.elementChanged((Element)node); - } + Element element = (Element) node; + if (delayedReconciler.shouldDelay(schema)) + { + delayedReconciler.elementChanged(element, schema); + } + else + { + XSDConcreteComponent concreteComponent = schema.getCorrespondingComponent(node); + concreteComponent.elementChanged(element); + } + } else if (node instanceof Document) { // The document changed so we may need to fix up the diff --git a/bundles/org.eclipse.wst.xsd.ui/src-adt/org/eclipse/wst/xsd/ui/internal/adt/outline/ADTContentOutlineProvider.java b/bundles/org.eclipse.wst.xsd.ui/src-adt/org/eclipse/wst/xsd/ui/internal/adt/outline/ADTContentOutlineProvider.java index e425871f41..ac6e76f24e 100644 --- a/bundles/org.eclipse.wst.xsd.ui/src-adt/org/eclipse/wst/xsd/ui/internal/adt/outline/ADTContentOutlineProvider.java +++ b/bundles/org.eclipse.wst.xsd.ui/src-adt/org/eclipse/wst/xsd/ui/internal/adt/outline/ADTContentOutlineProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2001, 2008 IBM Corporation and others. + * Copyright (c) 2001, 2009 IBM Corporation 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 @@ -11,7 +11,6 @@ package org.eclipse.wst.xsd.ui.internal.adt.outline; import org.eclipse.jface.viewers.ITreeContentProvider; -import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.wst.xsd.ui.internal.adt.facade.IADTObject; import org.eclipse.wst.xsd.ui.internal.adt.facade.IADTObjectListener; @@ -20,6 +19,7 @@ public class ADTContentOutlineProvider implements ITreeContentProvider, IADTObje { protected Viewer viewer = null; protected Object oldInput, newInput; + protected ADTContentOutlineRefreshJob refreshJob; public ADTContentOutlineProvider() { @@ -89,6 +89,11 @@ public class ADTContentOutlineProvider implements ITreeContentProvider, IADTObje { removeListener((IADTObject) input); } + if (refreshJob != null) + { + refreshJob.cancel(); + refreshJob = null; + } } /* (non-Javadoc) @@ -99,6 +104,11 @@ public class ADTContentOutlineProvider implements ITreeContentProvider, IADTObje this.viewer = viewer; this.oldInput = oldInput; this.newInput = newInput; + if (refreshJob != null) + { + refreshJob.cancel(); + } + refreshJob = new ADTContentOutlineRefreshJob(viewer); } /* (non-Javadoc) @@ -106,15 +116,7 @@ public class ADTContentOutlineProvider implements ITreeContentProvider, IADTObje */ public void propertyChanged(Object object, String property) { - if (viewer instanceof TreeViewer) - { - TreeViewer treeViewer = (TreeViewer) viewer; - if (treeViewer.getTree() != null && !treeViewer.getTree().isDisposed()) - { - treeViewer.refresh(object); - treeViewer.reveal(object); - } - } + refreshJob.refresh((IADTObject)object); } /** diff --git a/bundles/org.eclipse.wst.xsd.ui/src-adt/org/eclipse/wst/xsd/ui/internal/adt/outline/ADTContentOutlineRefreshJob.java b/bundles/org.eclipse.wst.xsd.ui/src-adt/org/eclipse/wst/xsd/ui/internal/adt/outline/ADTContentOutlineRefreshJob.java new file mode 100644 index 0000000000..bf04cf473a --- /dev/null +++ b/bundles/org.eclipse.wst.xsd.ui/src-adt/org/eclipse/wst/xsd/ui/internal/adt/outline/ADTContentOutlineRefreshJob.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2009 IBM Corporation 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.wst.xsd.ui.internal.adt.outline; + + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.PlatformUI; +import org.eclipse.wst.xsd.ui.internal.adapters.CategoryAdapter; +import org.eclipse.wst.xsd.ui.internal.adt.facade.IADTObject; + + +/** + * This job holds a queue of updates (affected nodes) for the XSD editor's + * outline view. When a new request comes in, the current run is cancelled, + * the new request is added to the queue, then the job is re-scheduled. + * This class is loosely based on RefreshStructureJob. + */ +class ADTContentOutlineRefreshJob extends Job +{ + /** + * The delay time in milliseconds. + */ + private static final long UPDATE_DELAY = 300; + + private final List nodesToRefresh = new ArrayList(5); + + private final TreeViewer viewer; + + public ADTContentOutlineRefreshJob(Viewer viewer) + { + super("Refreshing XSD outline"); //$NON-NLS-1$ + setPriority(Job.LONG); + setSystem(true); + this.viewer = (TreeViewer)viewer; + } + + private synchronized void addRefreshRequest(IADTObject adtObject) + { + if (nodesToRefresh.contains(adtObject)) + { + return; + } + + nodesToRefresh.add(adtObject); + } + + protected void canceling() + { + nodesToRefresh.clear(); + super.canceling(); + } + + private void doRefresh(final IADTObject adtObject) + { + final Display display = PlatformUI.getWorkbench().getDisplay(); + display.asyncExec(new Runnable() + { + public void run() + { + boolean isValidViewer = viewer != null && !viewer.getControl().isDisposed(); + if (isValidViewer) + { + viewer.refresh(adtObject); + + // Needlessly revealing the category nodes causes a lot of UI flicker. + + if (!(adtObject instanceof CategoryAdapter)) + { + viewer.reveal(adtObject); + } + } + } + }); + } + + private synchronized IADTObject[] getNodesToRefresh() + { + IADTObject[] toRefresh = new IADTObject [nodesToRefresh.size()]; + nodesToRefresh.toArray(toRefresh); + nodesToRefresh.clear(); + + return toRefresh; + } + + public void refresh(IADTObject adtObject) + { + if (adtObject == null) + { + return; + } + + addRefreshRequest(adtObject); + + schedule(UPDATE_DELAY); + } + + protected IStatus run(IProgressMonitor monitor) + { + IStatus status = Status.OK_STATUS; + try + { + performRefreshes(monitor); + } + finally + { + monitor.done(); + } + return status; + } + + private void performRefreshes(IProgressMonitor monitor) + { + IADTObject[] nodes = getNodesToRefresh(); + + for (int index = 0; index < nodes.length; index++) + { + if (monitor.isCanceled()) + { + throw new OperationCanceledException(); + } + IADTObject node = nodes[index]; + doRefresh(node); + } + } +}
\ No newline at end of file |