Bug 512601 - Add databinding observables for active workbench window,
active workbench page, and active workbench part
Change-Id: I8f43d5f4edd4cf8db9cc1976aed04b87cac96320
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/databinding/WorkbenchObservables.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/databinding/WorkbenchObservables.java
index f346cf4..babbafd 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/databinding/WorkbenchObservables.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/databinding/WorkbenchObservables.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2015 IBM Corporation and others.
+ * Copyright (c) 2009, 2017 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
@@ -9,15 +9,33 @@
* IBM Corporation - initial API and implementation
* Matthew Hall - initial API and implementation
* Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ * Sergey Prigogin (Google)
*******************************************************************************/
-
package org.eclipse.ui.databinding;
+import org.eclipse.core.databinding.observable.Diffs;
+import org.eclipse.core.databinding.observable.IObservable;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.value.AbstractObservableValue;
+import org.eclipse.core.databinding.observable.value.ComputedValue;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IAdapterManager;
import org.eclipse.core.runtime.Platform;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IPageListener;
+import org.eclipse.ui.IPartListener2;
+import org.eclipse.ui.IPartService;
+import org.eclipse.ui.IPropertyListener;
import org.eclipse.ui.ISelectionService;
+import org.eclipse.ui.IWindowListener;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPartConstants;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.services.IServiceLocator;
/**
@@ -95,4 +113,332 @@
WorkbenchProperties.adaptedValue(targetType)).observe(
selectionService);
}
+
+ /**
+ * Returns an observable value that tracks the active workbench window for
+ * the given workbench.
+ *
+ * @param workbench
+ * the workbench to get the observable for
+ * @return an observable value that tracks the active workbench window
+ * @since 3.110
+ */
+ public static IObservableValue<IWorkbenchWindow> observeActiveWorkbenchWindow(IWorkbench workbench) {
+ Assert.isNotNull(workbench);
+ return new ListeningValue<IWorkbenchWindow>() {
+ private final IWindowListener listener = new IWindowListener() {
+ @Override
+ public void windowActivated(IWorkbenchWindow window) {
+ protectedSetValue(window);
+ }
+
+ @Override
+ public void windowDeactivated(IWorkbenchWindow window) {
+ if (window == doGetValue()) {
+ protectedSetValue(null);
+ }
+ }
+
+ @Override
+ public void windowClosed(IWorkbenchWindow window) {
+ }
+
+ @Override
+ public void windowOpened(IWorkbenchWindow window) {
+ }
+ };
+
+ @Override
+ protected void startListening() {
+ workbench.addWindowListener(listener);
+ }
+
+ @Override
+ protected void stopListening() {
+ workbench.removeWindowListener(listener);
+ }
+
+ @Override
+ protected IWorkbenchWindow calculate() {
+ return workbench.getActiveWorkbenchWindow();
+ }
+ };
+ }
+
+ /**
+ * Returns an observable value that tracks the active workbench page for the
+ * given workbench window.
+ *
+ * @param window
+ * the workbench window to get the observable for
+ * @return an observable value that tracks the active workbench page
+ * @since 3.110
+ */
+ public static IObservableValue<IWorkbenchPage> observeActiveWorkbenchPage(IWorkbenchWindow window) {
+ Assert.isNotNull(window);
+ return new ListeningValue<IWorkbenchPage>() {
+ private final IPageListener listener = new IPageListener() {
+ @Override
+ public void pageActivated(IWorkbenchPage page) {
+ protectedSetValue(page);
+ }
+
+ @Override
+ public void pageClosed(IWorkbenchPage page) {
+ if (page == doGetValue()) {
+ protectedSetValue(null);
+ }
+ }
+
+ @Override
+ public void pageOpened(IWorkbenchPage page) {
+ }
+ };
+
+ @Override
+ protected void startListening() {
+ window.addPageListener(listener);
+ }
+
+ @Override
+ protected void stopListening() {
+ window.removePageListener(listener);
+ }
+
+ @Override
+ protected IWorkbenchPage calculate() {
+ return window.getActivePage();
+ }
+ };
+ }
+
+ /**
+ * Returns an observable value that tracks the active workbench part for the
+ * given part service.
+ *
+ * @param partService
+ * the part service to get the observable for, e.g. a workbench
+ * page
+ * @return an observable value that tracks the active workbench part
+ * @since 3.110
+ */
+ public static IObservableValue<IWorkbenchPartReference> observeActivePart(IPartService partService) {
+ Assert.isNotNull(partService);
+ return new ListeningValue<IWorkbenchPartReference>() {
+ private final IPartListener2 listener = new IPartListener2() {
+ @Override
+ public void partActivated(IWorkbenchPartReference partRef) {
+ protectedSetValue(partRef);
+ }
+
+ @Override
+ public void partDeactivated(IWorkbenchPartReference partRef) {
+ if (partRef == doGetValue()) {
+ protectedSetValue(null);
+ }
+ }
+
+ @Override
+ public void partBroughtToTop(IWorkbenchPartReference partRef) {
+ }
+
+ @Override
+ public void partClosed(IWorkbenchPartReference partRef) {
+ }
+
+ @Override
+ public void partOpened(IWorkbenchPartReference partRef) {
+ }
+
+ @Override
+ public void partHidden(IWorkbenchPartReference partRef) {
+ }
+
+ @Override
+ public void partVisible(IWorkbenchPartReference partRef) {
+ }
+
+ @Override
+ public void partInputChanged(IWorkbenchPartReference partRef) {
+ }
+ };
+
+ @Override
+ protected void startListening() {
+ partService.addPartListener(listener);
+ }
+
+ @Override
+ protected void stopListening() {
+ partService.removePartListener(listener);
+ }
+
+ @Override
+ protected IWorkbenchPartReference calculate() {
+ return partService.getActivePartReference();
+ }
+ };
+ }
+
+ /**
+ * Returns an observable value that tracks the active editor for the given
+ * part service.
+ *
+ * @param partService
+ * the part service to get the observable for, e.g. a workbench
+ * page
+ * @return an observable value that tracks the active editor
+ * @since 3.110
+ */
+ public static IObservableValue<IEditorReference> observeActiveEditor(IPartService partService) {
+ final IObservableValue<IWorkbenchPartReference> partObservable = observeActivePart(partService);
+ return ComputedValue.create(() -> {
+ IWorkbenchPartReference value = partObservable.getValue();
+ return value instanceof IEditorReference ? (IEditorReference) value : null;
+ });
+ }
+
+ /**
+ * Returns an observable value that tracks the editor input for the given
+ * editor.
+ *
+ * @param editor
+ * the editor to get the observable for
+ * @return an observable value that tracks the editor input
+ * @since 3.110
+ */
+ public static IObservableValue<IEditorInput> observeEditorInput(IEditorPart editor) {
+ Assert.isNotNull(editor);
+ return new ListeningValue<IEditorInput>() {
+ private final IPropertyListener listener = new IPropertyListener() {
+ @Override
+ public void propertyChanged(Object source, int propId) {
+ if (propId == IWorkbenchPartConstants.PROP_INPUT) {
+ protectedSetValue(editor.getEditorInput());
+ }
+ }
+ };
+
+ @Override
+ protected void startListening() {
+ editor.addPropertyListener(listener);
+ }
+
+ @Override
+ protected void stopListening() {
+ editor.removePropertyListener(listener);
+ }
+
+ @Override
+ protected IEditorInput calculate() {
+ return editor.getEditorInput();
+ }
+ };
+ }
+
+ /**
+ * A base class for creating observable values that track the state of a
+ * non-{@link IObservable} objects.
+ */
+ private abstract static class ListeningValue<T> extends AbstractObservableValue<T> {
+ private T value;
+ private boolean isListening;
+ private volatile boolean hasListeners;
+
+ @Override
+ protected final T doGetValue() {
+ // The value is not kept up to date when we are not listening.
+ if (isListening) {
+ return value;
+ }
+ return calculate();
+ }
+
+ /**
+ * Sets the value. Must be invoked in the {@link Realm} of the
+ * observable. Subclasses must call this method instead of
+ * {@link #setValue} or {@link #doSetValue}.
+ *
+ * @param value
+ * the value to set
+ */
+ protected final void protectedSetValue(T value) {
+ checkRealm();
+ if (!isListening)
+ throw new IllegalStateException();
+ if (this.value != value) {
+ fireValueChange(Diffs.createValueDiff(this.value, this.value = value));
+ }
+ }
+
+ @Override
+ protected final void firstListenerAdded() {
+ if (getRealm().isCurrent()) {
+ startListeningInternal();
+ } else {
+ getRealm().asyncExec(() -> {
+ if (hasListeners && !isListening) {
+ startListeningInternal();
+ }
+ });
+ }
+ hasListeners = true;
+ super.firstListenerAdded();
+ }
+
+ @Override
+ protected final void lastListenerRemoved() {
+ if (getRealm().isCurrent()) {
+ stopListeningInternal();
+ } else {
+ getRealm().asyncExec(() -> {
+ if (!hasListeners && isListening) {
+ stopListeningInternal();
+ }
+ });
+ }
+ hasListeners = false;
+ super.lastListenerRemoved();
+ }
+
+ private void startListeningInternal() {
+ isListening = true;
+ value = calculate();
+ startListening();
+ }
+
+ private void stopListeningInternal() {
+ isListening = false;
+ value = null;
+ stopListening();
+ }
+
+ /**
+ * Subclasses must override this method to attach listeners to the
+ * non-{@link IObservable} objects the state of which is tracked by this
+ * observable.
+ */
+ protected abstract void startListening();
+
+ /**
+ * Subclasses must override this method to detach listeners from the
+ * non-{@link IObservable} objects the state of which is tracked by this
+ * observable.
+ */
+ protected abstract void stopListening();
+
+ /**
+ * Subclasses must override this method to provide the object's value
+ * that will be used when the value is not set explicitly by
+ * {@link #doSetValue(Object)}.
+ *
+ * @return the object's value
+ */
+ protected abstract T calculate();
+
+ @Override
+ public Object getValueType() {
+ return null;
+ }
+ }
}
diff --git a/bundles/org.eclipse.ui.workbench/META-INF/MANIFEST.MF b/bundles/org.eclipse.ui.workbench/META-INF/MANIFEST.MF
index f98c1a7..7dad0c9 100644
--- a/bundles/org.eclipse.ui.workbench/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.ui.workbench/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.ui.workbench; singleton:=true
-Bundle-Version: 3.109.0.qualifier
+Bundle-Version: 3.110.0.qualifier
Bundle-ClassPath: .
Bundle-Activator: org.eclipse.ui.internal.WorkbenchPlugin
Bundle-ActivationPolicy: lazy
diff --git a/bundles/org.eclipse.ui.workbench/pom.xml b/bundles/org.eclipse.ui.workbench/pom.xml
index 8ec44ec..8eea13c 100644
--- a/bundles/org.eclipse.ui.workbench/pom.xml
+++ b/bundles/org.eclipse.ui.workbench/pom.xml
@@ -19,7 +19,7 @@
</parent>
<groupId>org.eclipse.ui</groupId>
<artifactId>org.eclipse.ui.workbench</artifactId>
- <version>3.109.0-SNAPSHOT</version>
+ <version>3.110.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
<properties>