[570839] [UI] Reopen CDOLob editors after a restart

https://bugs.eclipse.org/bugs/show_bug.cgi?id=570839
diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/plugin.xml b/plugins/org.eclipse.emf.cdo.explorer.ui/plugin.xml
index 3ac7802..c51de2b 100644
--- a/plugins/org.eclipse.emf.cdo.explorer.ui/plugin.xml
+++ b/plugins/org.eclipse.emf.cdo.explorer.ui/plugin.xml
@@ -855,6 +855,9 @@
     <factory
             id="org.eclipse.emf.cdo.explorer.ui.checkouts.CDOModelEditorInput.ElementFactory"
             class="org.eclipse.emf.cdo.explorer.ui.checkouts.CDOModelEditorInput$ElementFactory"/>
+    <factory
+            id="org.eclipse.emf.cdo.explorer.ui.checkouts.CDOCheckoutLobEditorInput.ElementFactory"
+            class="org.eclipse.emf.cdo.explorer.ui.checkouts.CDOCheckoutLobEditorInput$ElementFactory"/>
   </extension>
 
   <extension point="org.eclipse.emf.cdo.ui.editorOpeners">
diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutLobEditorInput.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutLobEditorInput.java
new file mode 100644
index 0000000..8253e62
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutLobEditorInput.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2020 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.explorer.ui.checkouts;
+
+import org.eclipse.emf.cdo.eresource.CDOFileResource;
+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.internal.ui.editor.CDOLobEditorInput;
+import org.eclipse.emf.cdo.internal.ui.editor.CDOLobStorage;
+import org.eclipse.emf.cdo.view.CDOView;
+
+import org.eclipse.net4j.util.ObjectUtil;
+import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
+import org.eclipse.net4j.util.ui.GlobalPartAdapter;
+
+import org.eclipse.emf.common.util.URI;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IElementFactory;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IPersistableElement;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.PartInitException;
+
+/**
+ * A text editor will consult {@link CDOLobStorage} for this input.
+ *
+ * @author Eike Stepper
+ */
+public class CDOCheckoutLobEditorInput extends CDOLobEditorInput implements IPersistableElement
+{
+  protected static final String URI_TAG = "uri";
+
+  protected static final String COMMIT_ON_SAVE_TAG = "commitOnSave";
+
+  public CDOCheckoutLobEditorInput(URI uri)
+  {
+    this(uri, false);
+  }
+
+  public CDOCheckoutLobEditorInput(URI uri, boolean commitOnSave)
+  {
+    super(getFile(uri), commitOnSave);
+    setURI(uri);
+  }
+
+  @Override
+  public IPersistableElement getPersistable()
+  {
+    return this;
+  }
+
+  @Override
+  public void saveState(IMemento memento)
+  {
+    URI uri = getURI();
+    memento.putString(URI_TAG, uri == null ? null : uri.toString());
+    memento.putBoolean(COMMIT_ON_SAVE_TAG, isCommitOnSave());
+  }
+
+  @Override
+  public String getFactoryId()
+  {
+    return ElementFactory.ID;
+  }
+
+  public static IEditorPart openEditor(IWorkbenchPage page, String editorID, URI uri) throws PartInitException
+  {
+    for (IEditorReference editorReference : page.getEditorReferences())
+    {
+      if (!ObjectUtil.equals(editorReference.getId(), editorID))
+      {
+        continue;
+      }
+
+      IEditorInput editorInput = editorReference.getEditorInput();
+      if (!(editorInput instanceof CDOCheckoutLobEditorInput))
+      {
+        continue;
+      }
+
+      CDOCheckoutLobEditorInput lobInput = (CDOCheckoutLobEditorInput)editorInput;
+      if (!lobInput.getURI().equals(uri))
+      {
+        continue;
+      }
+
+      IEditorPart editor = editorReference.getEditor(true);
+      page.activate(editor);
+      return editor;
+    }
+
+    IEditorInput lobInput = new CDOCheckoutLobEditorInput(uri, true);
+    return page.openEditor(lobInput, editorID);
+  }
+
+  private static CDOFileResource<?> getFile(URI uri)
+  {
+    String id = uri.authority();
+    CDOCheckout checkout = CDOExplorerUtil.getCheckout(id);
+    if (checkout != null)
+    {
+      checkout.open();
+
+      CDOView view = checkout.getView();
+      if (!view.isHistorical())
+      {
+        view = checkout.openTransaction();
+      }
+
+      CDOResourceNode node = view.getResourceNode(uri.path());
+      if (node instanceof CDOFileResource)
+      {
+        return (CDOFileResource<?>)node;
+      }
+    }
+
+    return null;
+  }
+
+  static
+  {
+    new GlobalPartAdapter()
+    {
+      @Override
+      public void partClosed(IWorkbenchPartReference partRef)
+      {
+        IWorkbenchPart part = partRef.getPart(false);
+        if (part instanceof IEditorPart)
+        {
+          IEditorPart editor = (IEditorPart)part;
+
+          IEditorInput input = editor.getEditorInput();
+          if (input instanceof CDOCheckoutLobEditorInput)
+          {
+            CDOCheckoutLobEditorInput lobInput = (CDOCheckoutLobEditorInput)input;
+
+            CDOView view = lobInput.getResource().cdoView();
+            CDOCheckout checkout = CDOExplorerUtil.getCheckout(view);
+            if (checkout == null || checkout.getView() != view)
+            {
+              LifecycleUtil.deactivate(view);
+            }
+          }
+        }
+      }
+    };
+  }
+
+  /**
+   * @author Eike Stepper
+   */
+  public static class ElementFactory implements IElementFactory
+  {
+    public static final String ID = "org.eclipse.emf.cdo.explorer.ui.checkouts.CDOCheckoutLobEditorInput.ElementFactory";
+
+    public ElementFactory()
+    {
+    }
+
+    @Override
+    public IAdaptable createElement(IMemento memento)
+    {
+      URI uri = URI.createURI(memento.getString(URI_TAG));
+      boolean commitOnSave = memento.getBoolean(COMMIT_ON_SAVE_TAG);
+      return new CDOCheckoutLobEditorInput(uri, commitOnSave);
+    }
+  }
+}
diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/actions/OpenWithActionProvider.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/actions/OpenWithActionProvider.java
index 18d682b..95c8179 100644
--- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/actions/OpenWithActionProvider.java
+++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/actions/OpenWithActionProvider.java
@@ -21,17 +21,15 @@
 import org.eclipse.emf.cdo.explorer.CDOExplorerUtil;
 import org.eclipse.emf.cdo.explorer.checkouts.CDOCheckout;
 import org.eclipse.emf.cdo.explorer.ui.bundle.OM;
+import org.eclipse.emf.cdo.explorer.ui.checkouts.CDOCheckoutLobEditorInput;
 import org.eclipse.emf.cdo.internal.explorer.CDOExplorerURIHandler;
 import org.eclipse.emf.cdo.internal.ui.dialogs.EditObjectDialog;
-import org.eclipse.emf.cdo.internal.ui.editor.CDOLobEditorInput;
 import org.eclipse.emf.cdo.transaction.CDOTransaction;
 import org.eclipse.emf.cdo.ui.CDOEditorOpener;
 import org.eclipse.emf.cdo.ui.CDOEditorUtil;
 import org.eclipse.emf.cdo.util.CDOUtil;
-import org.eclipse.emf.cdo.view.CDOView;
 
 import org.eclipse.net4j.util.ObjectUtil;
-import org.eclipse.net4j.util.om.OMPlatform;
 import org.eclipse.net4j.util.ui.UIUtil;
 
 import org.eclipse.emf.common.command.BasicCommandStack;
@@ -49,10 +47,7 @@
 import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.IActionBars;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.IPartListener;
 import org.eclipse.ui.IWorkbenchPage;
-import org.eclipse.ui.IWorkbenchPart;
 import org.eclipse.ui.PartInitException;
 import org.eclipse.ui.navigator.CommonActionProvider;
 import org.eclipse.ui.navigator.ICommonActionConstants;
@@ -65,8 +60,6 @@
  */
 public class OpenWithActionProvider extends CommonActionProvider
 {
-  private static final boolean OMIT_LOB_HANDLER_URI = OMPlatform.INSTANCE.isProperty("org.eclipse.emf.cdo.explorer.ui.omitLobHandlerURI");
-
   private ICommonViewerWorkbenchSite viewSite;
 
   private OpenAction openAction;
@@ -276,28 +269,6 @@
             editorOpener.openEditor(page, uri);
           }
         }
-        else
-        {
-          // Pair<CDOResourceLeaf, String> key = Pair.create(resourceLeaf, editorOpenerID);
-          //
-          // synchronized (EDITORS)
-          // {
-          // Object editor = EDITORS.get(key);
-          // if (editor != null)
-          // {
-          // if (editor != EDITOR_OPENING)
-          // {
-          // page.activate((IEditorPart)editor);
-          // }
-          //
-          // return;
-          // }
-          //
-          // EDITORS.put(key, EDITOR_OPENING);
-          // }
-          //
-          // openEditor(page, cdoObject, resourceLeaf, editorOpenerID, key);
-        }
       }
     }
     else if (resourceLeaf instanceof CDOFileResource)
@@ -305,62 +276,11 @@
       String editorID = CDOEditorUtil.getEffectiveEditorID(resourceLeaf);
       if (editorID != null)
       {
-        CDOView view = resourceLeaf.cdoView();
-        CDOCheckout checkout = CDOExplorerUtil.getCheckout(view);
-        CDOTransaction tx = view.isHistorical() ? null : checkout != null ? checkout.openTransaction() : view.getSession().openTransaction(view.getBranch());
-        CDOResourceLeaf txLeaf = tx == null ? resourceLeaf : tx.getObject(resourceLeaf);
+        URI uri = CDOExplorerURIHandler.createURI(resourceLeaf);
 
         try
         {
-          CDOLobEditorInput editorInput = (CDOLobEditorInput)CDOEditorUtil.createLobEditorInput(txLeaf, true);
-
-          if (checkout != null && !OMIT_LOB_HANDLER_URI)
-          {
-            editorInput.setURI(CDOExplorerURIHandler.createURI(checkout, txLeaf));
-          }
-
-          IEditorPart editor = page.openEditor(editorInput, editorID);
-
-          page.addPartListener(new IPartListener()
-          {
-            @Override
-            public void partClosed(IWorkbenchPart part)
-            {
-              if (part == editor)
-              {
-                if (tx != null)
-                {
-                  tx.close();
-                }
-
-                editor.getSite().getPage().removePartListener(this);
-              }
-            }
-
-            @Override
-            public void partActivated(IWorkbenchPart part)
-            {
-              // Do nothing.
-            }
-
-            @Override
-            public void partBroughtToTop(IWorkbenchPart part)
-            {
-              // Do nothing.
-            }
-
-            @Override
-            public void partDeactivated(IWorkbenchPart part)
-            {
-              // Do nothing.
-            }
-
-            @Override
-            public void partOpened(IWorkbenchPart part)
-            {
-              // Do nothing.
-            }
-          });
+          CDOCheckoutLobEditorInput.openEditor(page, editorID, uri);
         }
         catch (PartInitException ex)
         {
@@ -409,133 +329,6 @@
     return edited;
   }
 
-  // private static void registerEditor(IEditorPart editor, CDOView view, Pair<CDOResourceLeaf, String> key)
-  // {
-  // view.properties().put(WORKBENCH_PART_KEY, editor);
-  //
-  // synchronized (EDITORS)
-  // {
-  // EDITORS.put(key, editor);
-  // }
-  //
-  // synchronized (VIEWS)
-  // {
-  // VIEWS.put(editor, Pair.create(view, key));
-  // }
-  // }
-  //
-  // /**
-  // * @author Eike Stepper
-  // */
-  // private static final class WindowListener implements IWindowListener
-  // {
-  // public void windowOpened(IWorkbenchWindow window)
-  // {
-  // window.addPageListener(PAGE_LISTENER);
-  // }
-  //
-  // public void windowClosed(IWorkbenchWindow window)
-  // {
-  // window.removePageListener(PAGE_LISTENER);
-  // }
-  //
-  // public void windowActivated(IWorkbenchWindow window)
-  // {
-  // // Do nothing
-  // }
-  //
-  // public void windowDeactivated(IWorkbenchWindow window)
-  // {
-  // // Do nothing
-  // }
-  // }
-  //
-  // /**
-  // * @author Eike Stepper
-  // */
-  // private static final class PageListener implements IPageListener
-  // {
-  // public void pageOpened(IWorkbenchPage page)
-  // {
-  // page.addPartListener(PART_LISTENER);
-  // }
-  //
-  // public void pageClosed(IWorkbenchPage page)
-  // {
-  // page.removePartListener(PART_LISTENER);
-  // }
-  //
-  // public void pageActivated(IWorkbenchPage page)
-  // {
-  // // Do nothing
-  // }
-  // }
-  //
-  // /**
-  // * @author Eike Stepper
-  // */
-  // private static final class PartListener implements IPartListener2
-  // {
-  // public void partOpened(IWorkbenchPartReference partRef)
-  // {
-  // }
-  //
-  // public void partClosed(IWorkbenchPartReference partRef)
-  // {
-  // IWorkbenchPart part = partRef.getPart(false);
-  // if (part != null)
-  // {
-  // Pair<CDOView, Pair<CDOResourceLeaf, String>> pair;
-  // synchronized (VIEWS)
-  // {
-  // pair = VIEWS.remove(part);
-  // }
-  //
-  // if (pair != null)
-  // {
-  // CDOView view = pair.getElement1();
-  // view.close();
-  //
-  // Pair<CDOResourceLeaf, String> key = pair.getElement2();
-  // synchronized (EDITORS)
-  // {
-  // EDITORS.remove(key);
-  // }
-  // }
-  // }
-  // }
-  //
-  // public void partVisible(IWorkbenchPartReference partRef)
-  // {
-  // // Do nothing
-  // }
-  //
-  // public void partHidden(IWorkbenchPartReference partRef)
-  // {
-  // // Do nothing
-  // }
-  //
-  // public void partActivated(IWorkbenchPartReference partRef)
-  // {
-  // // Do nothing
-  // }
-  //
-  // public void partDeactivated(IWorkbenchPartReference partRef)
-  // {
-  // // Do nothing
-  // }
-  //
-  // public void partBroughtToTop(IWorkbenchPartReference partRef)
-  // {
-  // // Do nothing
-  // }
-  //
-  // public void partInputChanged(IWorkbenchPartReference partRef)
-  // {
-  // // Do nothing
-  // }
-  // }
-
   /**
    * @author Eike Stepper
    */
@@ -599,39 +392,4 @@
       openEditor(page, null, openableElement, editorOpener.getID());
     }
   }
-
-  // /**
-  // * @author Eike Stepper
-  // */
-  // private static class OpenFileAction extends Action
-  // {
-  // public static final String ID = OM.BUNDLE_ID + ".OpenFileAction"; //$NON-NLS-1$
-  //
-  // private final IWorkbenchPage page;
-  //
-  // private EObject openableElement;
-  //
-  // private String editorID;
-  //
-  // public OpenFileAction(IWorkbenchPage page, EObject openableElement, String editorID)
-  // {
-  // setId(ID);
-  //
-  // this.page = page;
-  // this.openableElement = openableElement;
-  // this.editorID = editorID;
-  //
-  // IEditorDescriptor editorDescriptor = PlatformUI.getWorkbench().getEditorRegistry().findEditor(editorID);
-  // setText(editorDescriptor.getLabel());
-  // setImageDescriptor(editorDescriptor.getImageDescriptor());
-  //
-  // setToolTipText("Edit this resource");
-  // }
-  //
-  // @Override
-  // public void run()
-  // {
-  // openEditor(page, null, openableElement, editorID);
-  // }
-  // }
 }
diff --git a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/CDOExplorerURIHandler.java b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/CDOExplorerURIHandler.java
index 3b09c8d..bc46524 100644
--- a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/CDOExplorerURIHandler.java
+++ b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/CDOExplorerURIHandler.java
@@ -219,6 +219,17 @@
     return null;
   }
 
+  public static URI createURI(CDOResourceNode node)
+  {
+    CDOCheckout checkout = CDOExplorerUtil.getCheckout(node);
+    if (checkout == null)
+    {
+      return null;
+    }
+
+    return createURI(checkout, node);
+  }
+
   public static URI createURI(CDOCheckout checkout, CDOResourceNode node)
   {
     String scheme = getScheme(node);
diff --git a/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/GlobalPartAdapter.java b/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/GlobalPartAdapter.java
new file mode 100644
index 0000000..04285fc
--- /dev/null
+++ b/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/GlobalPartAdapter.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2021 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.net4j.util.ui;
+
+import org.eclipse.net4j.util.collection.ConcurrentArray;
+import org.eclipse.net4j.util.internal.ui.bundle.OM;
+
+import org.eclipse.ui.IPageListener;
+import org.eclipse.ui.IPartListener2;
+import org.eclipse.ui.IWindowListener;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+import java.util.function.Consumer;
+
+/**
+ * @author Eike Stepper
+ * @since 3.10
+ */
+public class GlobalPartAdapter implements IWindowListener, IPageListener, IPartListener2
+{
+  private static final ConcurrentArray<GlobalPartAdapter> adapters = new ConcurrentArray<GlobalPartAdapter>()
+  {
+    @Override
+    protected GlobalPartAdapter[] newArray(int length)
+    {
+      return new GlobalPartAdapter[length];
+    }
+  };
+
+  public GlobalPartAdapter()
+  {
+    adapters.add(this);
+  }
+
+  public void dispose()
+  {
+    adapters.remove(this);
+  }
+
+  @Override
+  public void windowActivated(IWorkbenchWindow window)
+  {
+    // Subclasses may override.
+  }
+
+  @Override
+  public void windowDeactivated(IWorkbenchWindow window)
+  {
+    // Subclasses may override.
+  }
+
+  @Override
+  public void windowClosed(IWorkbenchWindow window)
+  {
+    // Subclasses may override.
+  }
+
+  @Override
+  public void windowOpened(IWorkbenchWindow window)
+  {
+    // Subclasses may override.
+  }
+
+  @Override
+  public void pageActivated(IWorkbenchPage page)
+  {
+    // Subclasses may override.
+  }
+
+  @Override
+  public void pageClosed(IWorkbenchPage page)
+  {
+    // Subclasses may override.
+  }
+
+  @Override
+  public void pageOpened(IWorkbenchPage page)
+  {
+    // Subclasses may override.
+  }
+
+  @Override
+  public void partActivated(IWorkbenchPartReference partRef)
+  {
+    // Subclasses may override.
+  }
+
+  @Override
+  public void partBroughtToTop(IWorkbenchPartReference partRef)
+  {
+    // Subclasses may override.
+  }
+
+  @Override
+  public void partClosed(IWorkbenchPartReference partRef)
+  {
+    // Subclasses may override.
+  }
+
+  @Override
+  public void partDeactivated(IWorkbenchPartReference partRef)
+  {
+    // Subclasses may override.
+  }
+
+  @Override
+  public void partOpened(IWorkbenchPartReference partRef)
+  {
+    // Subclasses may override.
+  }
+
+  @Override
+  public void partHidden(IWorkbenchPartReference partRef)
+  {
+    // Subclasses may override.
+  }
+
+  @Override
+  public void partVisible(IWorkbenchPartReference partRef)
+  {
+    // Subclasses may override.
+  }
+
+  @Override
+  public void partInputChanged(IWorkbenchPartReference partRef)
+  {
+    // Subclasses may override.
+  }
+
+  private static void notifyAdapters(Consumer<GlobalPartAdapter> consumer)
+  {
+    GlobalPartAdapter[] array = adapters.get();
+    if (array != null)
+    {
+      for (int i = 0; i < array.length; i++)
+      {
+        GlobalPartAdapter adapter = array[i];
+
+        try
+        {
+          consumer.accept(adapter);
+        }
+        catch (Exception ex)
+        {
+          OM.LOG.error(ex);
+        }
+      }
+    }
+  }
+
+  static
+  {
+    IPartListener2 partListener = new IPartListener2()
+    {
+      @Override
+      public void partOpened(IWorkbenchPartReference partRef)
+      {
+        notifyAdapters(a -> a.partOpened(partRef));
+      }
+
+      @Override
+      public void partClosed(IWorkbenchPartReference partRef)
+      {
+        notifyAdapters(a -> a.partClosed(partRef));
+      }
+
+      @Override
+      public void partActivated(IWorkbenchPartReference partRef)
+      {
+        notifyAdapters(a -> a.partActivated(partRef));
+      }
+
+      @Override
+      public void partDeactivated(IWorkbenchPartReference partRef)
+      {
+        notifyAdapters(a -> a.partDeactivated(partRef));
+      }
+
+      @Override
+      public void partBroughtToTop(IWorkbenchPartReference partRef)
+      {
+        notifyAdapters(a -> a.partBroughtToTop(partRef));
+      }
+
+      @Override
+      public void partHidden(IWorkbenchPartReference partRef)
+      {
+        notifyAdapters(a -> a.partHidden(partRef));
+      }
+
+      @Override
+      public void partVisible(IWorkbenchPartReference partRef)
+      {
+        notifyAdapters(a -> a.partVisible(partRef));
+      }
+
+      @Override
+      public void partInputChanged(IWorkbenchPartReference partRef)
+      {
+        notifyAdapters(a -> a.partInputChanged(partRef));
+      }
+    };
+
+    IPageListener pageListener = new IPageListener()
+    {
+      @Override
+      public void pageOpened(IWorkbenchPage page)
+      {
+        page.addPartListener(partListener);
+        notifyAdapters(a -> a.pageOpened(page));
+      }
+
+      @Override
+      public void pageClosed(IWorkbenchPage page)
+      {
+        page.removePartListener(partListener);
+        notifyAdapters(a -> a.pageClosed(page));
+      }
+
+      @Override
+      public void pageActivated(IWorkbenchPage page)
+      {
+        notifyAdapters(a -> a.pageActivated(page));
+      }
+    };
+
+    IWindowListener windowListener = new IWindowListener()
+    {
+      @Override
+      public void windowOpened(IWorkbenchWindow window)
+      {
+        window.addPageListener(pageListener);
+        notifyAdapters(a -> a.windowOpened(window));
+      }
+
+      @Override
+      public void windowClosed(IWorkbenchWindow window)
+      {
+        window.removePageListener(pageListener);
+        notifyAdapters(a -> a.windowOpened(window));
+      }
+
+      @Override
+      public void windowActivated(IWorkbenchWindow window)
+      {
+        notifyAdapters(a -> a.windowClosed(window));
+      }
+
+      @Override
+      public void windowDeactivated(IWorkbenchWindow window)
+      {
+        notifyAdapters(a -> a.windowDeactivated(window));
+      }
+    };
+
+    IWorkbench workbench = PlatformUI.getWorkbench();
+    workbench.addWindowListener(windowListener);
+  }
+}